You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2021/03/17 12:06:03 UTC

[ignite-3] branch main updated: IGNITE-13748: Schema configuration public API. (#2)

This is an automated email from the ASF dual-hosted git repository.

amashenkov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 3d54cf9  IGNITE-13748: Schema configuration public API. (#2)
3d54cf9 is described below

commit 3d54cf95080c1171cecffb544e94f98be2228a8c
Author: Andrew V. Mashenkov <AM...@users.noreply.github.com>
AuthorDate: Wed Mar 17 15:05:57 2021 +0300

    IGNITE-13748: Schema configuration public API. (#2)
---
 modules/README.md                                  |   1 +
 modules/api/README.md                              |   4 +
 modules/api/pom.xml                                |  37 +++
 .../main/java/org/apache/ignite/schema/Column.java |  45 ++++
 .../java/org/apache/ignite/schema/ColumnType.java  | 267 +++++++++++++++++++++
 .../org/apache/ignite/schema/ColumnarIndex.java    |  36 +++
 .../java/org/apache/ignite/schema/HashIndex.java   |  28 +++
 .../java/org/apache/ignite/schema/IndexColumn.java |  28 +++
 .../org/apache/ignite/schema/PartialIndex.java     |  35 +++
 .../org/apache/ignite/schema/PrimaryIndex.java     |  33 +++
 .../org/apache/ignite/schema/SchemaObject.java     |  28 +++
 .../java/org/apache/ignite/schema/SchemaTable.java |  66 +++++
 .../java/org/apache/ignite/schema/SortedIndex.java |  48 ++++
 .../apache/ignite/schema/SortedIndexColumn.java    |  28 +++
 .../java/org/apache/ignite/schema/TableIndex.java  |  35 +++
 .../ignite/schema/builder/HashIndexBuilder.java    |  40 +++
 .../ignite/schema/builder/PartialIndexBuilder.java |  61 +++++
 .../ignite/schema/builder/PrimaryIndexBuilder.java |  59 +++++
 .../ignite/schema/builder/SchemaObjectBuilder.java |  38 +++
 .../ignite/schema/builder/SchemaTableBuilder.java  |  62 +++++
 .../ignite/schema/builder/SortedIndexBuilder.java  |  80 ++++++
 .../ignite/schema/builder/TableColumnBuilder.java  |  59 +++++
 .../schema/modification/AlterColumnBuilder.java    |  76 ++++++
 .../modification/TableModificationBuilder.java     |  83 +++++++
 modules/schema/pom.xml                             |   6 +
 .../internal/schema/AbstractSchemaObject.java      |  50 ++++
 .../apache/ignite/internal/schema/ColumnImpl.java  |  76 ++++++
 .../ignite/internal/schema/HashIndexImpl.java      |  60 +++++
 .../ignite/internal/schema/IndexColumnImpl.java    |  41 ++++
 .../ignite/internal/schema/PartialIndexImpl.java   |  61 +++++
 .../ignite/internal/schema/PrimaryIndexImpl.java   |  52 ++++
 .../ignite/internal/schema/SchemaTableImpl.java    | 145 +++++++++++
 .../internal/schema/SortedIndexColumnImpl.java     |  53 ++++
 .../ignite/internal/schema/SortedIndexImpl.java    |  76 ++++++
 .../schema/builder/AbstractIndexBuilder.java       |  50 ++++
 .../schema/builder/HashIndexBuilderImpl.java       |  62 +++++
 .../schema/builder/PartialIndexBuilderImpl.java    | 113 +++++++++
 .../schema/builder/PrimaryKeyBuilderImpl.java      | 119 +++++++++
 .../schema/builder/SchemaTableBuilderImpl.java     | 133 ++++++++++
 .../schema/builder/SortedIndexBuilderImpl.java     | 147 ++++++++++++
 .../schema/builder/TableColumnBuilderImpl.java     |  84 +++++++
 .../modification/AlterColumnBuilderImpl.java       |  69 ++++++
 .../modification/TableModificationBuilderImpl.java |  94 ++++++++
 .../org/apache/ignite/schema/SchemaBuilders.java   | 108 +++++++++
 .../internal/schema/SchemaConfigurationTest.java   | 130 ++++++++++
 pom.xml                                            |   3 +-
 46 files changed, 3008 insertions(+), 1 deletion(-)

diff --git a/modules/README.md b/modules/README.md
index 091b7f0..05bf434 100644
--- a/modules/README.md
+++ b/modules/README.md
@@ -10,6 +10,7 @@ We prohibit cyclic dependencies between modules in order to simplify JIGSAW migr
 
 Module Name | Description
 ----------- | -----------
+[api](api/README.md)|Ignite public API
 [bytecode](bytecode/README.md)|Ignite Bytecode module.
 [cli](cli/README.md)|Ignite CLI implementation
 [cli-common](cli-common/README.md)|Shared interfaces definitions for pluggable CLIng
diff --git a/modules/api/README.md b/modules/api/README.md
new file mode 100644
index 0000000..2d26a0c
--- /dev/null
+++ b/modules/api/README.md
@@ -0,0 +1,4 @@
+# Ignite public API
+This module provides public types and interfaces for Ignite components.
+
+*TODO* Describe components API here.
\ No newline at end of file
diff --git a/modules/api/pom.xml b/modules/api/pom.xml
new file mode 100644
index 0000000..95a9778
--- /dev/null
+++ b/modules/api/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite-parent</artifactId>
+        <version>1</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>ignite-api</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+</project>
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/Column.java b/modules/api/src/main/java/org/apache/ignite/schema/Column.java
new file mode 100644
index 0000000..6ca400f
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/Column.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+/**
+ * Table column descriptor.
+ */
+public interface Column extends SchemaObject {
+    /**
+     * @return Column name.
+     */
+    @Override String name();
+
+    /**
+     * @return Column type.
+     */
+    ColumnType type();
+
+    /**
+     * {@code Nullable} flag.
+     *
+     * @return {@code True} if null-values is allowed, {@code false} otherwise.
+     */
+    boolean nullable();
+
+    /**
+     * @return Default column value.
+     */
+    Object defaultValue();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/ColumnType.java b/modules/api/src/main/java/org/apache/ignite/schema/ColumnType.java
new file mode 100644
index 0000000..11bc798
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/ColumnType.java
@@ -0,0 +1,267 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+import java.util.Objects;
+
+/**
+ * Predefined column types.
+ */
+@SuppressWarnings("PublicInnerClass")
+public class ColumnType {
+    /** 8-bit signed int. */
+    public static final ColumnType INT8 = new ColumnType(ColumnTypeSpec.INT8);
+
+    /** 16-bit signed int. */
+    public static final ColumnType INT16 = new ColumnType(ColumnTypeSpec.INT16);
+
+    /** 32-bit signed int. */
+    public static final ColumnType INT32 = new ColumnType(ColumnTypeSpec.INT32);
+
+    /** 64-bit signed int. */
+    public static final ColumnType INT64 = new ColumnType(ColumnTypeSpec.INT64);
+
+    /** 8-bit unsigned int. */
+    public static final ColumnType UINT8 = new ColumnType(ColumnTypeSpec.UINT8);
+
+    /** 16-bit unsigned int. */
+    public static final ColumnType UINT16 = new ColumnType(ColumnTypeSpec.UINT16);
+
+    /** 32-bit unsigned int. */
+    public static final ColumnType UINT32 = new ColumnType(ColumnTypeSpec.UINT32);
+
+    /** 64-bit unsigned int. */
+    public static final ColumnType UINT64 = new ColumnType(ColumnTypeSpec.UINT64);
+
+    /** 32-bit float. */
+    public static final ColumnType FLOAT = new ColumnType(ColumnTypeSpec.FLOAT);
+
+    /** 64-bit double. */
+    public static final ColumnType DOUBLE = new ColumnType(ColumnTypeSpec.DOUBLE);
+
+    /** 128-bit UUID. */
+    public static final ColumnType UUID = new ColumnType(ColumnTypeSpec.UUID);
+
+    /**
+     * Bitmask type factory method.
+     *
+     * @param bits Bitmask size in bits.
+     * @return Bitmap type.
+     */
+    public static VarLenColumnType bitmaskOf(int bits) {
+        return new VarLenColumnType(ColumnTypeSpec.BITMASK, bits);
+    }
+
+    /**
+     * String factory method.
+     *
+     * @return String type.
+     */
+    public static VarLenColumnType string() {
+        return stringOf(0);
+    }
+
+    /**
+     * String factory method for fix-sized string type.
+     *
+     * @param length String length in chars.
+     * @return String type.
+     */
+    public static VarLenColumnType stringOf(int length) {
+        return new VarLenColumnType(ColumnTypeSpec.STRING, length);
+    }
+
+    /**
+     * Blob type factory method.
+     *
+     * @return Blob type.
+     */
+    public static VarLenColumnType blobOf() {
+        return blobOf(0);
+    }
+
+    /**
+     * Blob type factory method for fix-sized blob.
+     *
+     * @param length Blob length in bytes.
+     * @return Blob type.
+     */
+    public static VarLenColumnType blobOf(int length) {
+        return new VarLenColumnType(ColumnTypeSpec.BLOB, length);
+    }
+
+    /**
+     * Decimal type factory method.
+     *
+     * @param precision Precision.
+     * @param scale Scale.
+     * @return Numeric type.
+     */
+    public static NumericColumnType number(int precision, int scale) {
+        return new NumericColumnType(ColumnTypeSpec.DECIMAL, precision, scale);
+    }
+
+    /**
+     * Column type of variable length.
+     */
+    public static class VarLenColumnType extends ColumnType {
+        /** Max length. */
+        private final int length;
+
+        /** Constructor. */
+        private VarLenColumnType(ColumnTypeSpec typeSpec, int length) {
+            super(typeSpec);
+
+            this.length = length;
+        }
+
+        /**
+         * @return Max column value length.
+         */
+        public int length() {
+            return length;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
+            if (!super.equals(o))
+                return false;
+            VarLenColumnType type = (VarLenColumnType)o;
+            return length == type.length;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return Objects.hash(super.hashCode(), length);
+        }
+    }
+
+    /**
+     * Numeric column type.
+     */
+    public static class NumericColumnType extends ColumnType {
+        /** Precision. */
+        private final int precision;
+
+        /** Scale. */
+        private final int scale;
+
+        /** Constructor. */
+        private NumericColumnType(ColumnTypeSpec typeSpec, int precision, int scale) {
+            super(typeSpec);
+
+            this.precision = precision;
+            this.scale = scale;
+        }
+
+        /**
+         * @return Precision.
+         */
+        public int precision() {
+            return precision;
+        }
+
+        /**
+         * @return Scale.
+         */
+        public int scale() {
+            return scale;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
+            if (!super.equals(o))
+                return false;
+            NumericColumnType type = (NumericColumnType)o;
+            return precision == type.precision &&
+                scale == type.scale;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return Objects.hash(super.hashCode(), precision, scale);
+        }
+    }
+
+    /**
+     * Column type spec.
+     */
+    public enum ColumnTypeSpec {
+        INT8,
+        INT16,
+        INT32,
+        INT64,
+
+        UINT8,
+        UINT16,
+        UINT32,
+        UINT64,
+
+        FLOAT,
+        DOUBLE,
+
+        DECIMAL,
+
+        UUID,
+
+        BITMASK,
+        STRING,
+        BLOB,
+    }
+
+    /** Type spec. */
+    private final ColumnTypeSpec typeSpec;
+
+    /** Constructor. */
+    private ColumnType(ColumnTypeSpec typeSpec) {
+        this.typeSpec = typeSpec;
+    }
+
+    /**
+     * @return Type spec.
+     */
+    public ColumnTypeSpec typeSpec() {
+        return typeSpec;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        ColumnType type = (ColumnType)o;
+
+        return typeSpec == type.typeSpec;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return Objects.hash(typeSpec);
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/ColumnarIndex.java b/modules/api/src/main/java/org/apache/ignite/schema/ColumnarIndex.java
new file mode 100644
index 0000000..5fdeb3e
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/ColumnarIndex.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+import java.util.List;
+
+public interface ColumnarIndex {
+    /**
+     * @return Index columns.
+     */
+    List<? extends IndexColumn> columns();
+
+    /**
+     * Returns all index columns: user defined + implicitly attched.
+     *
+     * @return Indexed columns.
+     */
+    default List<? extends IndexColumn> indexedColumns() {
+        return columns();
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/HashIndex.java b/modules/api/src/main/java/org/apache/ignite/schema/HashIndex.java
new file mode 100644
index 0000000..2a68e32
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/HashIndex.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+/**
+ * Hash index descriptor.
+ */
+public interface HashIndex extends TableIndex, ColumnarIndex {
+    /** {@inheritDoc} */
+    @Override default String type() {
+        return "HASH";
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/IndexColumn.java b/modules/api/src/main/java/org/apache/ignite/schema/IndexColumn.java
new file mode 100644
index 0000000..b944bdd
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/IndexColumn.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+/**
+ * Index column descriptor.
+ */
+public interface IndexColumn extends SchemaObject {
+    /**
+     * @return Column name.
+     */
+    @Override String name();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/PartialIndex.java b/modules/api/src/main/java/org/apache/ignite/schema/PartialIndex.java
new file mode 100644
index 0000000..92412d5
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/PartialIndex.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+/**
+ * Partial index descriptor.
+ */
+public interface PartialIndex extends SortedIndex {
+    /**
+     * Partial index expression.
+     *
+     * @return Expression.
+     */
+    String expr();
+
+    /** {@inheritDoc} */
+    @Override default String type() {
+        return "PARTIAL";
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/PrimaryIndex.java b/modules/api/src/main/java/org/apache/ignite/schema/PrimaryIndex.java
new file mode 100644
index 0000000..882ea98
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/PrimaryIndex.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+import java.util.List;
+
+/**
+ * Primary key index.
+ */
+public interface PrimaryIndex extends SortedIndex {
+    /** Primary key index name. */
+    String PRIMARY_KEY_INDEX_NAME = "PK";
+
+    /**
+     * @return Affinity columns
+     */
+    List<String> affinityColumns();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/SchemaObject.java b/modules/api/src/main/java/org/apache/ignite/schema/SchemaObject.java
new file mode 100644
index 0000000..8a924ec
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/SchemaObject.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+/**
+ * Schema object.
+ */
+public interface SchemaObject {
+    /**
+     * @return Schema object name.
+     */
+    String name();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/SchemaTable.java b/modules/api/src/main/java/org/apache/ignite/schema/SchemaTable.java
new file mode 100644
index 0000000..a71fbc3
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/SchemaTable.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+import java.util.Collection;
+import org.apache.ignite.schema.modification.TableModificationBuilder;
+
+/**
+ * Schema table descriptor.
+ */
+public interface SchemaTable extends SchemaObject {
+    /** Default schema name. */
+    String DEFAULT_SCHEMA_NAME = "PUBLIC";
+
+    /**
+     * @return Table name.
+     */
+    @Override String name();
+
+    /**
+     * @return Key columns.
+     */
+    Collection<Column> keyColumns();
+
+    /**
+     * @return Affinity columns.
+     */
+    Collection<Column> affinityColumns();
+
+    /**
+     * @return Value columns.
+     */
+    Collection<Column> valueColumns();
+
+    /**
+     * Schema name + Table name
+     *
+     * @return Canonical table name.
+     */
+    String canonicalName();
+
+    /**
+     * @return Table indexes.
+     */
+    Collection<TableIndex> indices();
+
+    /**
+     * @return Schema modification builder.
+     */
+    TableModificationBuilder toBuilder();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/SortedIndex.java b/modules/api/src/main/java/org/apache/ignite/schema/SortedIndex.java
new file mode 100644
index 0000000..8381ca0
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/SortedIndex.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+import java.util.List;
+
+/**
+ * Sorted index descriptor.
+ */
+public interface SortedIndex extends TableIndex, ColumnarIndex {
+    /** {@inheritDoc} */
+    @Override List<SortedIndexColumn> columns();
+
+    /** {@inheritDoc} */
+    @Override List<SortedIndexColumn> indexedColumns();
+
+    /**
+     * Unique index flag.
+     * <p>
+     * Limitation: Index MUST have all affinity columns declared explicitly.
+     * This requirement allows omitting cluster wide constraint checks.
+     *
+     * @return Unique flag.
+     */
+    default boolean unique() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override default String type() {
+        return "SORTED";
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/SortedIndexColumn.java b/modules/api/src/main/java/org/apache/ignite/schema/SortedIndexColumn.java
new file mode 100644
index 0000000..26c480b
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/SortedIndexColumn.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+/**
+ * Sorted index column.
+ */
+public interface SortedIndexColumn extends IndexColumn {
+    /**
+     * @return {@code True} for ascending sort order, {@code false} otherwise.
+     */
+    boolean asc();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/TableIndex.java b/modules/api/src/main/java/org/apache/ignite/schema/TableIndex.java
new file mode 100644
index 0000000..7345277
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/TableIndex.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+/**
+ * Table index base interface.
+ */
+public interface TableIndex extends SchemaObject {
+    /**
+     * @return Index name.
+     */
+    @Override String name();
+
+    /**
+     * Index type.
+     *
+     * @return Index type.
+     */
+    String type();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/builder/HashIndexBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/builder/HashIndexBuilder.java
new file mode 100644
index 0000000..6b82dff
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/builder/HashIndexBuilder.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.builder;
+
+import java.util.Map;
+import org.apache.ignite.schema.HashIndex;
+
+/**
+ * Hash index descriptor builder.
+ */
+public interface HashIndexBuilder extends SchemaObjectBuilder {
+    /**
+     * @param columns Indexed columns.
+     * @return {@code this} for chaining.
+     */
+    HashIndexBuilder withColumns(String... columns);
+
+    /** {@inheritDoc} */
+    @Override HashIndexBuilder withHints(Map<String, String> hints);
+
+    /**
+     * @return Hash index.
+     */
+    @Override HashIndex build();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/builder/PartialIndexBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/builder/PartialIndexBuilder.java
new file mode 100644
index 0000000..90f2eb5
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/builder/PartialIndexBuilder.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.builder;
+
+import java.util.Map;
+import org.apache.ignite.schema.PartialIndex;
+
+/**
+ * Partial index descriptor builder.
+ */
+public interface PartialIndexBuilder extends SortedIndexBuilder {
+    /**
+     * @param expr Partial index expression.
+     * @return {@code this} for chaining.
+     */
+    PartialIndexBuilder withExpression(String expr);
+
+    /** {@inheritDoc} */
+    @Override PartialIndexColumnBuilder addIndexColumn(String name);
+
+    /** {@inheritDoc} */
+    @Override PartialIndexBuilder withHints(Map<String, String> hints);
+
+    /**
+     * @return Partial index.
+     */
+    @Override PartialIndex build();
+
+    /**
+     * Index column builder.
+     */
+    @SuppressWarnings("PublicInnerClass")
+    interface PartialIndexColumnBuilder extends SortedIndexColumnBuilder {
+        /** {@inheritDoc} */
+        @Override PartialIndexColumnBuilder desc();
+
+        /** {@inheritDoc} */
+        @Override PartialIndexColumnBuilder asc();
+
+        /** {@inheritDoc} */
+        @Override PartialIndexColumnBuilder withName(String name);
+
+        /** {@inheritDoc} */
+        @Override PartialIndexBuilder done();
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/builder/PrimaryIndexBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/builder/PrimaryIndexBuilder.java
new file mode 100644
index 0000000..eb4a555
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/builder/PrimaryIndexBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.builder;
+
+import org.apache.ignite.schema.PrimaryIndex;
+
+/**
+ * Hash index descriptor builder.
+ */
+public interface PrimaryIndexBuilder extends SortedIndexBuilder {
+    /**
+     * Sets affinity columns.
+     *
+     * @param cols Affinity columns
+     * @return Primary index builder.
+     */
+    PrimaryIndexBuilder withAffinityColumns(String... cols);
+
+    /** {@inheritDoc} */
+    @Override PrimaryIndexColumnBuilder addIndexColumn(String name);
+
+    /**
+     * @return Primary index.
+     */
+    @Override PrimaryIndex build();
+
+    /**
+     * Index column builder.
+     */
+    @SuppressWarnings("PublicInnerClass")
+    interface PrimaryIndexColumnBuilder extends SortedIndexColumnBuilder {
+        /** {@inheritDoc} */
+        @Override PrimaryIndexColumnBuilder desc();
+
+        /** {@inheritDoc} */
+        @Override PrimaryIndexColumnBuilder asc();
+
+        /** {@inheritDoc} */
+        @Override PrimaryIndexColumnBuilder withName(String name);
+
+        /** {@inheritDoc} */
+        @Override PrimaryIndexBuilder done();
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/builder/SchemaObjectBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/builder/SchemaObjectBuilder.java
new file mode 100644
index 0000000..c8f352f
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/builder/SchemaObjectBuilder.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.builder;
+
+import java.util.Map;
+
+/**
+ * Builder base interface.
+ */
+public interface SchemaObjectBuilder {
+    /**
+     * Provide hints to builder.
+     *
+     * @param hints Hints.
+     * @return {@code This} for chaining.
+     */
+    SchemaObjectBuilder withHints(Map<String, String> hints);
+
+    /**
+     * @return Built object.
+     */
+    Object build();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/builder/SchemaTableBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/builder/SchemaTableBuilder.java
new file mode 100644
index 0000000..7e5a204
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/builder/SchemaTableBuilder.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.builder;
+
+import java.util.Map;
+import org.apache.ignite.schema.Column;
+import org.apache.ignite.schema.PrimaryIndex;
+import org.apache.ignite.schema.SchemaTable;
+import org.apache.ignite.schema.TableIndex;
+
+/**
+ * Table descriptor builder.
+ */
+public interface SchemaTableBuilder extends SchemaObjectBuilder {
+    /**
+     * @param columns Table columns.
+     * @return {@code This} for chaining.
+     */
+    SchemaTableBuilder columns(Column... columns);
+
+    /**
+     * Adds an index.
+     *
+     * @param index Table index.
+     * @return {@code This} for chaining.
+     */
+    SchemaTableBuilder withIndex(TableIndex index);
+
+    /**
+     * Shortcut method for adding {@link PrimaryIndex} via {@link #withIndex(TableIndex)}
+     *
+     * @param colName Key column name.
+     * @return {@code This} for chaining.
+     */
+    SchemaTableBuilder withPrimaryKey(String colName);
+
+    /** {@inheritDoc} */
+    @Override SchemaTableBuilder withHints(Map<String, String> hints);
+
+    /**
+     * Builds table schema.
+     *
+     * @return Table schema.
+     */
+    @Override SchemaTable build();
+
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/builder/SortedIndexBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/builder/SortedIndexBuilder.java
new file mode 100644
index 0000000..96dcd65
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/builder/SortedIndexBuilder.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.builder;
+
+import java.util.Map;
+import org.apache.ignite.schema.SortedIndex;
+
+/**
+ * Sorted index descriptor builder.
+ */
+public interface SortedIndexBuilder extends SchemaObjectBuilder {
+    /**
+     * Sets unique flag to {@code true}.
+     *
+     * @return {@code this} for chaining.
+     */
+    SortedIndexBuilder unique();
+
+    /**
+     * Adds a column to index.
+     *
+     * @param name Table column name.
+     * @return Index builder.
+     */
+    SortedIndexColumnBuilder addIndexColumn(String name);
+
+    /** {@inheritDoc} */
+    @Override SortedIndexBuilder withHints(Map<String, String> hints);
+
+    /**
+     * @return Sorted index.
+     */
+    @Override SortedIndex build();
+
+    /**
+     * Index column builder.
+     */
+    @SuppressWarnings("PublicInnerClass")
+    interface SortedIndexColumnBuilder {
+        /**
+         * Sets descending sort order.
+         *
+         * @return {@code this} for chaining.
+         */
+        SortedIndexColumnBuilder desc();
+
+        /**
+         * Sets ascending sort order.
+         *
+         * @return {@code this} for chaining.
+         */
+        SortedIndexColumnBuilder asc();
+
+        /**
+         * @param name Column name.
+         * @return {@code this} for chaining.
+         */
+        SortedIndexColumnBuilder withName(String name);
+
+        /**
+         * @return Parent builder for chaining.
+         */
+        SortedIndexBuilder done();
+    }
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/builder/TableColumnBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/builder/TableColumnBuilder.java
new file mode 100644
index 0000000..ed6b40e
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/builder/TableColumnBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.builder;
+
+import java.util.Map;
+import org.apache.ignite.schema.Column;
+
+/**
+ * Table column builder.
+ */
+public interface TableColumnBuilder extends SchemaObjectBuilder {
+    /**
+     * Mark column as nullable.
+     *
+     * @return {@code this} for chaining.
+     */
+    TableColumnBuilder asNullable();
+
+    /**
+     * Mark column as non-nullable.
+     *
+     * @return {@code this} for chaining.
+     */
+    TableColumnBuilder asNonNull();
+
+    /**
+     * Sets column default value.
+     *
+     * @param defValue Default value.
+     * @return {@code this} for chaining.
+     */
+    TableColumnBuilder withDefaultValue(Object defValue);
+
+    /** {@inheritDoc} */
+    @Override TableColumnBuilder withHints(Map<String, String> hints);
+
+    /**
+     * Builds column.
+     *
+     * @return Built column.
+     */
+    @Override Column build();
+}
+
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/modification/AlterColumnBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/modification/AlterColumnBuilder.java
new file mode 100644
index 0000000..94ff66e
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/modification/AlterColumnBuilder.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.modification;
+
+import org.apache.ignite.schema.ColumnType;
+
+/**
+ * Alter column builder.
+ *
+ * NOTE: Only safe actions that can be applied automatically on-fly are allowed.
+ */
+public interface AlterColumnBuilder {
+    /**
+     * Renames a column.
+     *
+     * @param newName New column name.
+     * @return {@code this} for chaining.
+     */
+    AlterColumnBuilder withNewName(String newName);
+
+    /**
+     * Convert column to a new type.
+     * <p>
+     * Note: New type must be compatible with old.
+     *
+     * @param newType New column type.
+     * @return {@code this} for chaining.
+     */
+    AlterColumnBuilder convertTo(ColumnType newType);
+
+    /**
+     * Sets new column default value.
+     *
+     * @param defaultValue Default value.
+     * @return {@code this} for chaining.
+     */
+    AlterColumnBuilder withNewDefault(Object defaultValue);
+
+    /**
+     * Mark column as nullable.
+     *
+     * @return {@code this} for chaining.
+     */
+    AlterColumnBuilder asNullable();
+
+    /**
+     * Mark column as non-nullable.
+     *
+     * Note: Replacement param is mandatory, all previously stored 'nulls'
+     * will be treated as replacement value on read.
+     *
+     * @param replacement Non-null value, that 'null' will be converted to.
+     * @return {@code this} for chaining.
+     */
+    AlterColumnBuilder asNonNullable(Object replacement);
+
+    /**
+     * @return Parent builder.
+     */
+    TableModificationBuilder done();
+}
diff --git a/modules/api/src/main/java/org/apache/ignite/schema/modification/TableModificationBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/modification/TableModificationBuilder.java
new file mode 100644
index 0000000..9e7f903
--- /dev/null
+++ b/modules/api/src/main/java/org/apache/ignite/schema/modification/TableModificationBuilder.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.modification;
+
+import org.apache.ignite.schema.Column;
+import org.apache.ignite.schema.TableIndex;
+
+/**
+ * Collect schema modification commands and pass them to manager to create a schema upgrade script.
+ */
+public interface TableModificationBuilder {
+    /**
+     * Adds new value column.
+     *
+     * @param column Column.
+     * @return {@code this} for chaining.
+     */
+    TableModificationBuilder addColumn(Column column);
+
+    /**
+     * Adds new non-affinity key column.
+     *
+     * @param column Column.
+     * @return {@code this} for chaining.
+     */
+    TableModificationBuilder addKeyColumn(Column column);
+
+    /**
+     * Creates alter column builder..
+     *
+     * @param columnName Column name.
+     * @return Alter column builder.
+     */
+    AlterColumnBuilder alterColumn(String columnName);
+
+    /**
+     * Drops value column.
+     * <p>
+     * Note: Key column drop is not allowed.
+     *
+     * @param columnName Column.
+     * @return {@code this} for chaining.
+     */
+    TableModificationBuilder dropColumn(String columnName);
+
+    /**
+     * Adds new table index.
+     *
+     * @param index Table index.
+     * @return {@code this} for chaining.
+     */
+    TableModificationBuilder addIndex(TableIndex index);
+
+    /**
+     * Drops table index.
+     * <p>
+     * Note: PK can't be dropped.
+     *
+     * @param indexName Index name.
+     * @return {@code this} for chaining.
+     */
+    TableModificationBuilder dropIndex(String indexName);
+
+    /**
+     * Apply changes.
+     */
+    void apply();
+}
diff --git a/modules/schema/pom.xml b/modules/schema/pom.xml
index 7fe8861..bddbd85 100644
--- a/modules/schema/pom.xml
+++ b/modules/schema/pom.xml
@@ -35,6 +35,12 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
             <artifactId>ignite-bytecode</artifactId>
             <version>${project.version}</version>
         </dependency>
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/AbstractSchemaObject.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/AbstractSchemaObject.java
new file mode 100644
index 0000000..9ad2d9f
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/AbstractSchemaObject.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import org.apache.ignite.schema.SchemaObject;
+
+/**
+ * Schema object base class.
+ */
+public abstract class AbstractSchemaObject implements SchemaObject {
+    /** Schema object name. */
+    private final String name;
+
+    /**
+     * Constructor.
+     *
+     * @param name Schema object name.
+     */
+    protected AbstractSchemaObject(String name) {
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String name() {
+        return name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "SchemaObject[" +
+            "name='" + name + '\'' +
+            "class=" + getClass().getName() +
+            ']';
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/ColumnImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/ColumnImpl.java
new file mode 100644
index 0000000..24dfc4b
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/ColumnImpl.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import org.apache.ignite.schema.Column;
+import org.apache.ignite.schema.ColumnType;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Table column.
+ */
+public class ColumnImpl extends AbstractSchemaObject implements Column {
+    /** Column type. */
+    private final ColumnType type;
+
+    /** Nullable flag. */
+    private final boolean nullable;
+
+    /** Default value. */
+    private final Object defVal;
+
+    /**
+     * Constructor.
+     *
+     * @param name Column name.
+     * @param type Column type.
+     * @param nullable Nullable flag.
+     * @param defVal Default value.
+     */
+    public ColumnImpl(String name, ColumnType type, boolean nullable, @Nullable Object defVal) {
+        super(name);
+        this.type = type;
+        this.nullable = nullable;
+        this.defVal = defVal;
+    }
+
+    /** {@inheritDoc} */
+    @Override public ColumnType type() {
+        return type;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean nullable() {
+        return nullable;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object defaultValue() {
+        return defVal;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "ColumnImpl[" +
+            "name='" + name() + '\'' +
+            ", type=" + type +
+            ", nullable=" + nullable +
+            ", default=" + defVal +
+            ']';
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/HashIndexImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/HashIndexImpl.java
new file mode 100644
index 0000000..cbac7bd
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/HashIndexImpl.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.ignite.schema.HashIndex;
+import org.apache.ignite.schema.IndexColumn;
+
+/**
+ * Hash index.
+ */
+public class HashIndexImpl extends AbstractSchemaObject implements HashIndex {
+    /** Index columns. */
+    private final List<IndexColumn> columns;
+
+    /**
+     * Constructor.
+     *
+     * @param name Index name.
+     * @param columns Index columns.
+     */
+    public HashIndexImpl(String name, String[] columns) {
+        super(name);
+
+        this.columns = Arrays.stream(columns).map(IndexColumnImpl::new).collect(Collectors.toUnmodifiableList());
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+    @Override public List<IndexColumn> columns() {
+        return columns;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "TableIndex[" +
+            "type=HASH, " +
+            "name='" + name() + '\'' +
+            ", columns=[" + columns.stream().map(IndexColumn::name).collect(Collectors.joining()) + ']' +
+            ']';
+    }
+
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/IndexColumnImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/IndexColumnImpl.java
new file mode 100644
index 0000000..a7fe166
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/IndexColumnImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import org.apache.ignite.schema.IndexColumn;
+
+/**
+ * Non-ordered index column.
+ */
+class IndexColumnImpl extends AbstractSchemaObject implements IndexColumn {
+    /**
+     * Constructor.
+     *
+     * @param name Column name.
+     */
+    IndexColumnImpl(String name) {
+        super(name);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Column[" +
+            "name='" + name() + '\'' +
+            ']';
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/PartialIndexImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/PartialIndexImpl.java
new file mode 100644
index 0000000..09c2295
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/PartialIndexImpl.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.ignite.schema.IndexColumn;
+import org.apache.ignite.schema.PartialIndex;
+import org.apache.ignite.schema.SortedIndexColumn;
+
+/**
+ * Partial table index.
+ */
+public class PartialIndexImpl extends SortedIndexImpl implements PartialIndex {
+    /** Expression. */
+    private final String expr;
+
+    /**
+     * Constructor.
+     *
+     * @param name Index name.
+     * @param columns Index columns.
+     * @param uniq Unique flag.
+     * @param expr Partial index expression.
+     */
+    public PartialIndexImpl(String name, List<SortedIndexColumn> columns, boolean uniq, String expr) {
+        super(name, columns, uniq);
+
+        this.expr = expr;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String expr() {
+        return expr;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "PartialIndex[" +
+            "name='" + name() + '\'' +
+            ", type=PARTIAL" +
+            ", expr='" + expr + '\'' +
+            ", columns=[" + columns().stream().map(IndexColumn::toString).collect(Collectors.joining(",")) + ']' +
+            ']';
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/PrimaryIndexImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/PrimaryIndexImpl.java
new file mode 100644
index 0000000..c99340d
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/PrimaryIndexImpl.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.ignite.schema.PrimaryIndex;
+import org.apache.ignite.schema.SortedIndexColumn;
+
+/**
+ * Primary key index.
+ */
+public class PrimaryIndexImpl extends SortedIndexImpl implements PrimaryIndex {
+    /** Affinity columns. */
+    private final List<String> affCols;
+
+    /**
+     * Constructor.
+     *
+     * @param cols Index columns.
+     * @param affCols Affinity columns.
+     */
+    public PrimaryIndexImpl(List<SortedIndexColumn> cols, List<String> affCols) {
+        super(PrimaryIndex.PRIMARY_KEY_INDEX_NAME, cols, true);
+        this.affCols = Collections.unmodifiableList(affCols);
+    }
+
+    /** {@inheritDoc} */
+    @Override public List<String> affinityColumns() {
+        return affCols;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String type() {
+        return "PK";
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaTableImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaTableImpl.java
new file mode 100644
index 0000000..c4180f9
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaTableImpl.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.schema.modification.TableModificationBuilderImpl;
+import org.apache.ignite.schema.Column;
+import org.apache.ignite.schema.IndexColumn;
+import org.apache.ignite.schema.PrimaryIndex;
+import org.apache.ignite.schema.SchemaTable;
+import org.apache.ignite.schema.TableIndex;
+import org.apache.ignite.schema.modification.TableModificationBuilder;
+
+/**
+ * Table.
+ */
+@SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+public class SchemaTableImpl extends AbstractSchemaObject implements SchemaTable {
+    /** Schema name. */
+    private final String schemaName;
+
+    /** Key columns. */
+    private final LinkedHashMap<String, Column> cols;
+
+    /** Indices. */
+    private final Map<String, TableIndex> indices;
+
+    /** Cached key columns. */
+    private final List<Column> keyCols;
+
+    /** Cached key affinity columns. */
+    private final List<Column> affCols;
+
+    /** Cached value columns. */
+    private final List<Column> valCols;
+
+    /**
+     * Constructor.
+     *
+     * @param schemaName Schema name.
+     * @param tableName Table name.
+     * @param cols Columns.
+     * @param indices Indices.
+     */
+    public SchemaTableImpl(
+        String schemaName,
+        String tableName,
+        final LinkedHashMap<String, Column> cols,
+        final Map<String, TableIndex> indices
+    ) {
+        super(tableName);
+
+        this.schemaName = schemaName;
+        this.cols = cols;
+        this.indices = indices;
+
+        final PrimaryIndex pkIndex = (PrimaryIndex)indices.get(PrimaryIndex.PRIMARY_KEY_INDEX_NAME);
+        final Set<String> pkColNames = pkIndex.columns().stream().map(IndexColumn::name).collect(Collectors.toSet());
+
+        assert pkIndex != null;
+
+        keyCols = pkIndex.columns().stream().map(c -> cols.get(c.name())).collect(Collectors.toUnmodifiableList());
+        affCols = pkIndex.affinityColumns().stream().map(cols::get).collect(Collectors.toUnmodifiableList());
+        valCols = cols.values().stream().filter(c -> !pkColNames.contains(c.name())).collect(Collectors.toUnmodifiableList());
+
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<Column> keyColumns() {
+        return keyCols;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<Column> affinityColumns() {
+        return affCols;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<Column> valueColumns() {
+        return valCols;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String canonicalName() {
+        return schemaName + '.' + name();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<TableIndex> indices() {
+        return Collections.unmodifiableCollection(indices.values());
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableModificationBuilder toBuilder() {
+        return new TableModificationBuilderImpl(this);
+    }
+
+    /**
+     * @param name Column name.
+     * @return {@code True} if column with given name already exists, {@code false} otherwise.
+     */
+    public boolean hasColumn(String name) {
+        return cols.containsKey(name);
+    }
+
+    /**
+     * @param name Column name.
+     * @return {@code True} if key column with given name already exists, {@code false} otherwise.
+     */
+    public boolean hasKeyColumn(String name) {
+        return keyCols.stream().anyMatch(c -> c.name().equals(name));
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "SchemaTable[" +
+            "name='" + name() + '\'' +
+            ", keyCols=" + keyCols.stream().map(Column::name).collect(Collectors.joining(",")) +
+            ", affCols=" + affCols.stream().map(Column::name).collect(Collectors.joining(",")) +
+            ", column=" + cols.values() +
+            ", indices=" + indices.values() +
+            ']';
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SortedIndexColumnImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SortedIndexColumnImpl.java
new file mode 100644
index 0000000..8df6ae7
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SortedIndexColumnImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import org.apache.ignite.schema.SortedIndexColumn;
+
+/**
+ * Ordered index column.
+ */
+public class SortedIndexColumnImpl extends AbstractSchemaObject implements SortedIndexColumn {
+    /** Sort order. */
+    private final boolean asc;
+
+    /**
+     * Constructor.
+     *
+     * @param name Column name.
+     * @param asc Sort order flag.
+     */
+    public SortedIndexColumnImpl(String name, boolean asc) {
+        super(name);
+
+        this.asc = asc;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean asc() {
+        return asc;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Column[" +
+            "name='" + name() + '\'' +
+            ", order=" + (asc ? "asc" : "desc") +
+            ']';
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SortedIndexImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SortedIndexImpl.java
new file mode 100644
index 0000000..115f46c
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SortedIndexImpl.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.ignite.schema.IndexColumn;
+import org.apache.ignite.schema.SortedIndex;
+import org.apache.ignite.schema.SortedIndexColumn;
+
+/**
+ * Sorted index.
+ */
+public class SortedIndexImpl extends AbstractSchemaObject implements SortedIndex {
+    /** Columns. */
+    private final List<SortedIndexColumn> cols;
+
+    /** Unique flag. */
+    private final boolean uniq;
+
+    /**
+     * Constructor.
+     *
+     * @param name Index name.
+     * @param cols Index columns.
+     * @param uniq Unique flag.
+     */
+    public SortedIndexImpl(String name, List<SortedIndexColumn> cols, boolean uniq) {
+        super(name);
+
+        this.cols = Collections.unmodifiableList(cols);
+        this.uniq = uniq;
+    }
+
+    /** {@inheritDoc} */
+    @Override public List<SortedIndexColumn> columns() {
+        return cols;
+    }
+
+    /** {@inheritDoc} */
+    @Override public List<SortedIndexColumn> indexedColumns() {
+        return cols;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean unique() {
+        return uniq;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "SortedIndex[" +
+            "name='" + name() + '\'' +
+            ", type=SORTED" +
+            ", uniq=" + uniq +
+            ", columns=[" + columns().stream().map(IndexColumn::toString).collect(Collectors.joining(",")) +
+            "]]";
+    }
+
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/AbstractIndexBuilder.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/AbstractIndexBuilder.java
new file mode 100644
index 0000000..3225c28
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/AbstractIndexBuilder.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.builder;
+
+import java.util.Collections;
+import java.util.Map;
+import org.apache.ignite.schema.builder.SchemaObjectBuilder;
+
+/**
+ * Index base class.
+ */
+public abstract class AbstractIndexBuilder implements SchemaObjectBuilder {
+    /** Index name. */
+    protected final String name;
+
+    /** Builder hints. */
+    protected Map<String, String> hints;
+
+    /**
+     * Constructor.
+     *
+     * @param name Index name.
+     */
+    AbstractIndexBuilder(String name) {
+        this.name = name;
+    }
+
+
+    /** {@inheritDoc} */
+    @Override public AbstractIndexBuilder withHints(Map<String, String> hints) {
+        this.hints = Collections.unmodifiableMap(hints);
+
+        return this;
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/HashIndexBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/HashIndexBuilderImpl.java
new file mode 100644
index 0000000..9013f66
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/HashIndexBuilderImpl.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.builder;
+
+import java.util.Map;
+import org.apache.ignite.internal.schema.HashIndexImpl;
+import org.apache.ignite.schema.HashIndex;
+import org.apache.ignite.schema.builder.HashIndexBuilder;
+
+/**
+ * Hash index builder.
+ */
+public class HashIndexBuilderImpl extends AbstractIndexBuilder implements HashIndexBuilder {
+    /** Index columns. */
+    private String[] columns;
+
+    /**
+     * Constructor.
+     *
+     * @param name Index name.
+     */
+    public HashIndexBuilderImpl(String name) {
+        super(name);
+    }
+
+    /** {@inheritDoc} */
+    @Override public HashIndexBuilder withColumns(String... columns) {
+        this.columns = columns.clone();
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public HashIndexBuilderImpl withHints(Map<String, String> hints) {
+        super.withHints(hints);
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public HashIndex build() {
+        assert columns != null;
+        assert columns.length > 0;
+
+        return new HashIndexImpl(name, columns);
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/PartialIndexBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/PartialIndexBuilderImpl.java
new file mode 100644
index 0000000..80aea18
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/PartialIndexBuilderImpl.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.builder;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.schema.PartialIndexImpl;
+import org.apache.ignite.internal.schema.SortedIndexColumnImpl;
+import org.apache.ignite.schema.PartialIndex;
+import org.apache.ignite.schema.builder.PartialIndexBuilder;
+
+/**
+ * Partial index builder.
+ */
+public class PartialIndexBuilderImpl extends SortedIndexBuilderImpl implements PartialIndexBuilder {
+    /** Partial index expression. */
+    private String expr;
+
+    /**
+     * Constructor.
+     *
+     * @param idxName Index name.
+     */
+    public PartialIndexBuilderImpl(String idxName) {
+        super(idxName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public PartialIndexBuilderImpl withHints(Map<String, String> hints) {
+        super.withHints(hints);
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public PartialIndex build() {
+        assert expr != null && !expr.trim().isEmpty();
+
+        return new PartialIndexImpl(
+            name,
+            cols.values().stream().map(c -> new SortedIndexColumnImpl(c.name, c.asc)).collect(Collectors.toList()),
+            unique,
+            expr
+        );
+    }
+
+    /** {@inheritDoc} */
+    @Override public PartialIndexBuilder withExpression(String expr) {
+        this.expr = expr;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public PartialIndexColumnBuilderImpl addIndexColumn(String name) {
+        return new PartialIndexColumnBuilderImpl(this).withName(name);
+    }
+
+    /**
+     * Index column builder.
+     */
+    private static class PartialIndexColumnBuilderImpl extends SortedIndexColumnBuilderImpl implements PartialIndexColumnBuilder {
+        /**
+         * Constructor.
+         *
+         * @param idxBuilder Index builder.
+         */
+        PartialIndexColumnBuilderImpl(PartialIndexBuilderImpl idxBuilder) {
+            super(idxBuilder);
+        }
+
+        /** {@inheritDoc} */
+        @Override public PartialIndexColumnBuilderImpl desc() {
+            super.desc();
+
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public PartialIndexColumnBuilderImpl asc() {
+            super.asc();
+
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public PartialIndexColumnBuilderImpl withName(String name) {
+            super.withName(name);
+
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public PartialIndexBuilderImpl done() {
+            return (PartialIndexBuilderImpl)super.done();
+        }
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/PrimaryKeyBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/PrimaryKeyBuilderImpl.java
new file mode 100644
index 0000000..be1783d
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/PrimaryKeyBuilderImpl.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.builder;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.schema.PrimaryIndexImpl;
+import org.apache.ignite.schema.PrimaryIndex;
+import org.apache.ignite.schema.SortedIndexColumn;
+import org.apache.ignite.schema.builder.PrimaryIndexBuilder;
+
+import static org.apache.ignite.schema.PrimaryIndex.PRIMARY_KEY_INDEX_NAME;
+
+/**
+ * Primary index builder.
+ */
+public class PrimaryKeyBuilderImpl extends SortedIndexBuilderImpl implements PrimaryIndexBuilder {
+    /** */
+    private List<String> affCols;
+
+    /**
+     * Constructor.
+     */
+    public PrimaryKeyBuilderImpl() {
+        super(PRIMARY_KEY_INDEX_NAME);
+
+        super.unique();
+    }
+
+    /** {@inheritDoc} */
+    @Override public PrimaryKeyBuilderImpl withHints(Map<String, String> hints) {
+        super.withHints(hints);
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public PrimaryKeyBuilderImpl unique() {
+        return this; // Nothing to do.
+    }
+
+    @Override public PkIndexColumnBuilderImpl addIndexColumn(String name) {
+        return new PkIndexColumnBuilderImpl(this).withName(name);
+    }
+
+    /** {@inheritDoc} */
+    @Override public PrimaryKeyBuilderImpl withAffinityColumns(String... affCols) {
+        this.affCols = Arrays.asList(affCols);
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public PrimaryIndex build() {
+        if (affCols == null)
+            affCols = columns().stream().map(SortedIndexColumn::name).collect(Collectors.toList());
+        else
+            assert affCols.stream().allMatch(cols::containsKey) : "Affinity column should be a valid PK index column.";
+
+        return new PrimaryIndexImpl(columns(), affCols);
+    }
+
+    /**
+     * Index column builder.
+     */
+    private static class PkIndexColumnBuilderImpl extends SortedIndexColumnBuilderImpl implements PrimaryIndexColumnBuilder {
+        /**
+         * Constructor.
+         *
+         * @param parent Parent builder.
+         */
+        PkIndexColumnBuilderImpl(PrimaryKeyBuilderImpl parent) {
+            super(parent);
+        }
+
+        /** {@inheritDoc} */
+        @Override public PkIndexColumnBuilderImpl withName(String name) {
+            super.withName(name);
+
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public PkIndexColumnBuilderImpl desc() {
+            super.desc();
+
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public PkIndexColumnBuilderImpl asc() {
+            super.asc();
+
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public PrimaryKeyBuilderImpl done() {
+            return (PrimaryKeyBuilderImpl)super.done();
+        }
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/SchemaTableBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/SchemaTableBuilderImpl.java
new file mode 100644
index 0000000..405f30e
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/SchemaTableBuilderImpl.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.builder;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.apache.ignite.internal.schema.SchemaTableImpl;
+import org.apache.ignite.schema.Column;
+import org.apache.ignite.schema.ColumnarIndex;
+import org.apache.ignite.schema.IndexColumn;
+import org.apache.ignite.schema.PrimaryIndex;
+import org.apache.ignite.schema.SchemaBuilders;
+import org.apache.ignite.schema.SchemaTable;
+import org.apache.ignite.schema.TableIndex;
+import org.apache.ignite.schema.builder.SchemaTableBuilder;
+
+import static org.apache.ignite.schema.PrimaryIndex.PRIMARY_KEY_INDEX_NAME;
+
+/**
+ * Table builder.
+ */
+public class SchemaTableBuilderImpl implements SchemaTableBuilder {
+    /** Schema name. */
+    private final String schemaName;
+
+    /** Table name. */
+    private final String tableName;
+
+    /** Columns. */
+    private final LinkedHashMap<String, Column> columns = new LinkedHashMap<>();
+
+    /** Indices. */
+    private final Map<String, TableIndex> indices = new HashMap<>();
+
+    /**
+     * Constructor.
+     *
+     * @param schemaName Schema name.
+     * @param tableName Table name.
+     */
+    public SchemaTableBuilderImpl(String schemaName, String tableName) {
+        this.schemaName = schemaName;
+        this.tableName = tableName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public SchemaTableBuilderImpl columns(Column... columns) {
+        for (int i = 0; i < columns.length; i++) {
+            if (this.columns.put(columns[i].name(), columns[i]) != null)
+                throw new IllegalStateException("Column with same name already exists: columnName=" + columns[i].name());
+        }
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public SchemaTableBuilder withIndex(TableIndex index) {
+        if (index instanceof PrimaryIndex) {
+            if (!PRIMARY_KEY_INDEX_NAME.equals(index.name()))
+                throw new IllegalArgumentException("Not valid index name for a primary index: " + index.name());
+        }
+        else if (PRIMARY_KEY_INDEX_NAME.equals(index.name()))
+            throw new IllegalArgumentException("Not valid index name for a secondary index: " + index.name());
+
+        if (indices.put(index.name(), index) != null)
+            throw new IllegalArgumentException("Index with same name already exists: " + index.name());
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public SchemaTableBuilder withPrimaryKey(String colName) {
+        withIndex(SchemaBuilders.pkIndex().addIndexColumn(colName).done().build());
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public SchemaTableBuilder withHints(Map<String, String> hints) {
+        // No op.
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public SchemaTable build() {
+        assert schemaName != null : "Table name was not specified.";
+        assert columns.size() >= 2 : "Key or/and value columns was not defined.";
+
+        validateIndices();
+
+        return new SchemaTableImpl(
+            schemaName,
+            tableName,
+            columns,
+            Collections.unmodifiableMap(indices)
+        );
+    }
+
+    /**
+     * Validate indices.
+     */
+    private void validateIndices() {
+        assert indices.values().stream()
+            .filter(ColumnarIndex.class::isInstance)
+            .map(ColumnarIndex.class::cast)
+            .flatMap(idx -> idx.columns().stream())
+            .map(IndexColumn::name)
+            .allMatch(columns::containsKey) : "Index column doesn't exists in schema.";
+
+        assert indices.containsKey(PRIMARY_KEY_INDEX_NAME) : "Primary key index is not configured.";
+        assert !((PrimaryIndex)indices.get(PRIMARY_KEY_INDEX_NAME)).affinityColumns().isEmpty() : "Primary key must have one affinity column at least.";
+
+        // Note: E.g. functional index is not columnar index as it index an expression result only.
+        assert indices.values().stream().allMatch(ColumnarIndex.class::isInstance) : "Columnar indices are supported only.";
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/SortedIndexBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/SortedIndexBuilderImpl.java
new file mode 100644
index 0000000..fba1e47
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/SortedIndexBuilderImpl.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.builder;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.schema.SortedIndexColumnImpl;
+import org.apache.ignite.internal.schema.SortedIndexImpl;
+import org.apache.ignite.schema.SortedIndex;
+import org.apache.ignite.schema.SortedIndexColumn;
+import org.apache.ignite.schema.builder.SortedIndexBuilder;
+
+/**
+ * Sorted index builder.
+ */
+public class SortedIndexBuilderImpl extends AbstractIndexBuilder implements SortedIndexBuilder {
+    /** Index columns. */
+    protected final Map<String, SortedIndexColumnBuilderImpl> cols = new HashMap<>();
+
+    /** Unique flag. */
+    protected boolean unique;
+
+    /**
+     * Constructor.
+     *
+     * @param name Index name.
+     */
+    public SortedIndexBuilderImpl(String name) {
+        super(name);
+    }
+
+    /** {@inheritDoc} */
+    @Override public SortedIndexBuilderImpl withHints(Map<String, String> hints) {
+        super.withHints(hints);
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public SortedIndexColumnBuilderImpl addIndexColumn(String name) {
+        return new SortedIndexColumnBuilderImpl(this).withName(name);
+    }
+
+    /** {@inheritDoc} */
+    @Override public SortedIndexBuilderImpl unique() {
+        unique = true;
+
+        return this;
+    }
+
+    /**
+     * @param idxBuilder Index builder.
+     */
+    protected void addIndexColumn(SortedIndexColumnBuilderImpl idxBuilder) {
+        if (cols.put(idxBuilder.name(), idxBuilder) != null)
+            throw new IllegalArgumentException("Index with same name already exists: " + idxBuilder.name());
+    }
+
+    /**
+     * @return Index columns.
+     */
+    public List<SortedIndexColumn> columns() {
+        return cols.values().stream().map(c -> new SortedIndexColumnImpl(c.name, c.asc)).collect(Collectors.toList());
+    }
+
+    /** {@inheritDoc} */
+    @Override public SortedIndex build() {
+        assert !cols.isEmpty();
+
+        return new SortedIndexImpl(
+            name,
+            columns(),
+            unique);
+    }
+
+    /**
+     * Index column builder.
+     */
+    protected static class SortedIndexColumnBuilderImpl implements SortedIndexColumnBuilder {
+        /** Index builder. */
+        private final SortedIndexBuilderImpl parent;
+
+        /** Columns name. */
+        protected String name;
+
+        /** Index order flag. */
+        protected boolean asc = true;
+
+        /**
+         * Constructor.
+         *
+         * @param parent Parent builder.
+         */
+        SortedIndexColumnBuilderImpl(SortedIndexBuilderImpl parent) {
+            this.parent = parent;
+        }
+
+        /** {@inheritDoc} */
+        @Override public SortedIndexColumnBuilderImpl desc() {
+            asc = false;
+
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public SortedIndexColumnBuilderImpl asc() {
+            asc = true;
+
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public SortedIndexColumnBuilderImpl withName(String name) {
+            this.name = name;
+
+            return this;
+        }
+
+        public String name() {
+            return name;
+        }
+
+        /** {@inheritDoc} */
+        @Override public SortedIndexBuilderImpl done() {
+            parent.addIndexColumn(this);
+
+            return parent;
+        }
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/TableColumnBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/TableColumnBuilderImpl.java
new file mode 100644
index 0000000..130f3d3
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/builder/TableColumnBuilderImpl.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.builder;
+
+import java.util.Map;
+import org.apache.ignite.internal.schema.ColumnImpl;
+import org.apache.ignite.schema.Column;
+import org.apache.ignite.schema.ColumnType;
+import org.apache.ignite.schema.builder.TableColumnBuilder;
+
+/**
+ * Column builder.
+ */
+public class TableColumnBuilderImpl implements TableColumnBuilder {
+    /** Column name. */
+    private final String colName;
+
+    /** Column type. */
+    private final ColumnType colType;
+
+    /** Nullable flag. */
+    private boolean nullable;
+
+    /** Default value. */
+    private Object defValue;
+
+    /**
+     * Constructor.
+     * @param colName Column name.
+     * @param colType Column type.
+     */
+    public TableColumnBuilderImpl(String colName, ColumnType colType) {
+        this.colName = colName;
+        this.colType = colType;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableColumnBuilderImpl asNullable() {
+        nullable = true;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableColumnBuilderImpl asNonNull() {
+        nullable = false;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableColumnBuilderImpl withDefaultValue(Object defValue) {
+        this.defValue = defValue;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableColumnBuilderImpl withHints(Map<String, String> hints) {
+        // No op.
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Column build() {
+        return new ColumnImpl(colName, colType, nullable, defValue);
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/modification/AlterColumnBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/modification/AlterColumnBuilderImpl.java
new file mode 100644
index 0000000..3b3a6a8
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/modification/AlterColumnBuilderImpl.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.modification;
+
+import org.apache.ignite.schema.ColumnType;
+import org.apache.ignite.schema.modification.AlterColumnBuilder;
+import org.apache.ignite.schema.modification.TableModificationBuilder;
+
+/**
+ * Alter column builder.
+ */
+class AlterColumnBuilderImpl implements AlterColumnBuilder {
+    /** Table modification builder. */
+    private final TableModificationBuilderImpl tableBuilder;
+
+    /**
+     * Constructor.
+     *
+     * @param tableBuilder Table modification builder.
+     */
+    AlterColumnBuilderImpl(TableModificationBuilderImpl tableBuilder) {
+        this.tableBuilder = tableBuilder;
+    }
+
+    /** {@inheritDoc} */
+    @Override public AlterColumnBuilder withNewName(String newName) {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public AlterColumnBuilder convertTo(ColumnType newType) {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public AlterColumnBuilder withNewDefault(Object defaultValue) {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public AlterColumnBuilder asNullable() {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public AlterColumnBuilder asNonNullable(Object replacement) {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableModificationBuilder done() {
+        return tableBuilder;
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/modification/TableModificationBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/modification/TableModificationBuilderImpl.java
new file mode 100644
index 0000000..b1b875c
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/modification/TableModificationBuilderImpl.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.modification;
+
+import org.apache.ignite.internal.schema.SchemaTableImpl;
+import org.apache.ignite.schema.Column;
+import org.apache.ignite.schema.PrimaryIndex;
+import org.apache.ignite.schema.TableIndex;
+import org.apache.ignite.schema.modification.AlterColumnBuilder;
+import org.apache.ignite.schema.modification.TableModificationBuilder;
+
+/**
+ * Table modification builder.
+ */
+public class TableModificationBuilderImpl implements TableModificationBuilder {
+    /** Table. */
+    private final SchemaTableImpl table;
+
+    /**
+     * Constructor.
+     *
+     * @param table Table.
+     */
+    public TableModificationBuilderImpl(SchemaTableImpl table) {
+        this.table = table;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableModificationBuilder addColumn(Column column) {
+        if (table.hasColumn(column.name()))
+            throw new IllegalStateException("Duplicate column: name='" + column.name() + '\'');
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableModificationBuilder addKeyColumn(Column column) {
+        if (table.hasColumn(column.name()))
+            throw new IllegalStateException("Duplicate column: name=" + column.name() + '\'');
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public AlterColumnBuilder alterColumn(String columnName) {
+        return new AlterColumnBuilderImpl(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableModificationBuilder dropColumn(String columnName) {
+        if (table.hasKeyColumn(columnName))
+            throw new IllegalStateException("Can't drop key column: name=" + columnName);
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableModificationBuilder addIndex(TableIndex index) {
+        assert !PrimaryIndex.PRIMARY_KEY_INDEX_NAME.equals(index.name());
+
+        if (table.indices().stream().anyMatch(i -> i.name().equals(index.name())))
+            throw new IllegalStateException("Index already exists: name=" + index.name() + '\'');
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public TableModificationBuilder dropIndex(String indexName) {
+        if (PrimaryIndex.PRIMARY_KEY_INDEX_NAME.equals(indexName))
+            throw new IllegalStateException("Can't drop primary key index: name=" + indexName);
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void apply() {
+
+    }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/schema/SchemaBuilders.java b/modules/schema/src/main/java/org/apache/ignite/schema/SchemaBuilders.java
new file mode 100644
index 0000000..ac2b646
--- /dev/null
+++ b/modules/schema/src/main/java/org/apache/ignite/schema/SchemaBuilders.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema;
+
+import org.apache.ignite.internal.schema.builder.HashIndexBuilderImpl;
+import org.apache.ignite.internal.schema.builder.PartialIndexBuilderImpl;
+import org.apache.ignite.internal.schema.builder.PrimaryKeyBuilderImpl;
+import org.apache.ignite.internal.schema.builder.SchemaTableBuilderImpl;
+import org.apache.ignite.internal.schema.builder.SortedIndexBuilderImpl;
+import org.apache.ignite.internal.schema.builder.TableColumnBuilderImpl;
+import org.apache.ignite.schema.builder.HashIndexBuilder;
+import org.apache.ignite.schema.builder.PartialIndexBuilder;
+import org.apache.ignite.schema.builder.PrimaryIndexBuilder;
+import org.apache.ignite.schema.builder.SchemaTableBuilder;
+import org.apache.ignite.schema.builder.SortedIndexBuilder;
+import org.apache.ignite.schema.builder.TableColumnBuilder;
+
+/**
+ * Schema builder helper.
+ */
+public final class SchemaBuilders {
+    /**
+     * Create table descriptor from classes.
+     *
+     * @param schemaName Schema name.
+     * @param tableName Table name.
+     * @param keyClass Key class.
+     * @param valueClass Value class.
+     * @return Table descriptor for given key-value pair.
+     */
+    public static SchemaTable buildSchema(String schemaName, String tableName, Class<?> keyClass, Class<?> valueClass) {
+        // TODO IGNITE-13749: implement schema generation from classes.
+
+        return null;
+    }
+
+    /**
+     * Creates table descriptor builder.
+     *
+     * @param schemaName Schema name.
+     * @param tableName Table name.
+     * @return Table descriptor builder.
+     */
+    public static SchemaTableBuilder tableBuilder(String schemaName, String tableName) {
+        return new SchemaTableBuilderImpl(schemaName, tableName);
+    }
+
+    /**
+     * Creates table column builder.
+     *
+     * @param name Column name.
+     * @param type Column type.
+     * @return Column builder.
+     */
+    public static TableColumnBuilder column(String name, ColumnType type) {
+        return new TableColumnBuilderImpl(name, type);
+    }
+
+    /**
+     * @return Primary index builder.
+     */
+    public static PrimaryIndexBuilder pkIndex() {
+        return new PrimaryKeyBuilderImpl();
+    }
+
+    /**
+     * @param name Index name.
+     * @return Sorted index builder.
+     */
+    public static SortedIndexBuilder sortedIndex(String name) {
+        return new SortedIndexBuilderImpl(name);
+    }
+
+    /**
+     * @param name Index name.
+     * @return Partial index builder.
+     */
+    public static PartialIndexBuilder partialIndex(String name) {
+        return new PartialIndexBuilderImpl(name);
+    }
+
+    /**
+     * @param name Index name.
+     * @return Hash index builder.
+     */
+    public static HashIndexBuilder hashIndex(String name) {
+        return new HashIndexBuilderImpl(name);
+    }
+
+    // Stub.
+    private SchemaBuilders() {
+    }
+}
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/SchemaConfigurationTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/SchemaConfigurationTest.java
new file mode 100644
index 0000000..50dffcf
--- /dev/null
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/SchemaConfigurationTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema;
+
+import java.util.Map;
+import org.apache.ignite.schema.ColumnType;
+import org.apache.ignite.schema.SchemaBuilders;
+import org.apache.ignite.schema.SchemaTable;
+import org.apache.ignite.schema.builder.SchemaTableBuilder;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ */
+public class SchemaConfigurationTest {
+    /**
+     *
+     */
+    @Test
+    public void testInitialSchema() {
+        final SchemaTableBuilder builder = SchemaBuilders.tableBuilder(SchemaTable.DEFAULT_SCHEMA_NAME, "table1");
+
+        builder
+            .columns(
+                // Declaring columns in user order.
+                SchemaBuilders.column("id", ColumnType.INT64).build(),
+                SchemaBuilders.column("label", ColumnType.stringOf(2)).withDefaultValue("AI").build(),
+                SchemaBuilders.column("name", ColumnType.string()).asNonNull().build(),
+                SchemaBuilders.column("data", ColumnType.blobOf(255)).asNullable().build(),
+                SchemaBuilders.column("affId", ColumnType.INT32).build()
+            )
+
+            .withIndex(
+                SchemaBuilders.pkIndex()  // Declare index column in order.
+                    .addIndexColumn("id").desc().done()
+                    .addIndexColumn("affId").asc().done()
+                    .addIndexColumn("name").asc().done()
+                    .withAffinityColumns("affId") // Optional affinity declaration. If not set, all columns will be affinity cols.
+                    .build()
+            )
+
+            // 'withIndex' single entry point allows extended index support.
+            // E.g. we may want to support Geo-index later with some plugin.
+            .withIndex(
+                SchemaBuilders.sortedIndex("idx_1_sorted")
+                    .addIndexColumn("id").desc().done()
+                    .addIndexColumn("name").asc().done()
+                    .withHints(Map.of("INLINE_SIZE", "42", "INLINE_STRATEGY", "INLINE_HASH")) // In-line key-hash as well.
+                    .build()
+            )
+
+            .withIndex(
+                SchemaBuilders.partialIndex("idx_2_partial")
+                    .addIndexColumn("id").desc().done()
+                    .addIndexColumn("name").asc().done()
+                    .withExpression("id > 0")
+                    .withHints(Map.of("INLINE_COLUMNS", "id"))
+                    .build()
+            )
+
+            .withIndex(
+                SchemaBuilders.hashIndex("idx_3_hash")
+                    .withColumns("id", "affId")
+                    .build()
+            )
+
+            .build();
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testSchemaModification() {
+        final SchemaTable table = SchemaBuilders.tableBuilder("PUBLIC", "table1")
+            .columns(
+                // Declaring columns in user order.
+                SchemaBuilders.column("id", ColumnType.INT64).build(),
+                SchemaBuilders.column("name", ColumnType.string()).build()
+            )
+            .withPrimaryKey("id")
+            .build();
+
+        table.toBuilder()
+            .addColumn(
+                SchemaBuilders.column("firstName", ColumnType.string())
+                    .asNonNull()
+                    .build()
+            )
+            .addKeyColumn( // It looks safe to add non-affinity column to key.
+                SchemaBuilders.column("subId", ColumnType.string())
+                    .asNonNull()
+                    .build()
+            )
+
+            .alterColumn("firstName")
+            .withNewName("lastName")
+            .withNewDefault("ivanov")
+            .asNullable()
+            .convertTo(ColumnType.stringOf(100))
+            .done()
+
+            .dropColumn("name") // Key column can't be dropped.
+
+            .addIndex(
+                SchemaBuilders.sortedIndex("sortedIdx")
+                    .addIndexColumn("subId").done()
+                    .withHints(Map.of("INLINE_SIZE", "73"))
+                    .build()
+            )
+
+            .dropIndex("hash_idx")
+            .apply();
+    }
+}
diff --git a/pom.xml b/pom.xml
index 914b843..4a225d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,14 +34,15 @@
     <packaging>pom</packaging>
 
     <modules>
+        <module>modules/api</module>
         <module>modules/bytecode</module>
         <module>modules/cli</module>
         <module>modules/cli-common</module>
         <module>modules/configuration</module>
         <module>modules/configuration-annotation-processor</module>
+        <module>modules/network</module>
         <module>modules/rest</module>
         <module>modules/runner</module>
-        <module>modules/network</module>
         <module>modules/schema</module>
     </modules>
 </project>