You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

IDIEP-123
AuthorMikhail Pochatkin  
Sponsor Mikhail Pochatkin 
Created
StatusDRAFT


Motivation

In addition o SQL DDL commands, provide a simple, low-feature and type-safe Java API for initial tables generation from POJO. 
Support custom annotations and simple builders. This feature should work seamlessly with existing Mapper interface (keyValueView and
recordView). It will give developers the ability to work in the way they used to - create tables from POJO and build indexes without
forcing them to use SQL for basic operations.


This proposal is successor of `QueryEntity` and `CacheConfiguration.setIndexedTypes()`  which was supported by AI2

Description

Apache Ignite is very idiomatic in Java, while `QueryEntity` in AI 2.x is technically low value - it's a convenient way 
to work with tables and pojo mapping. Besides, AI 3.x already has table keyValueViews that maps pojo but lacks features 
to easily instantiate tables.

We are not trying to achieve functionality of altering tables, schema migration tools and track changes, just a simple 
self-sufficient way of initial schema generation from POJO classes (prototyping, testing etc. purposes).

Statements, properties, expressions should be covered:
- CREATE ZONE
- CREATE TABLE
- CREATE INDEX
- DROP ZONE/TABLE/INDEX
- Column definition, length, precision, scale, nullability, defaults.

The Flow 

  • The user uses annotations (or builders as an alternative).
  • The client (ignite entry point - client or embedded mode) generates the SQL statements.
  •  The client runs the SQL as usual.
  •  The user uses KeyValueView, recordView or ResultSet as usual (those APIs should support `@Column` annotation as well).
  •  The implementation should be fail-fast and throw exceptions on any ambiguity.

API

@Target(TYPE)
@Retention(RUNTIME)
public @interface Table {
    String name() default "";
    Index[] indexes() default {};
    IndexType primaryKeyType() default IndexType.DEFAULT;
    ColocateBy colocateBy() default @ColocateBy(columnList = "");
    Class<?> zone() default DefaultZone.class;
}

public interface DefaultZone { /*marker inerface*/ }

public enum SortOrder {
    DEFAULT, // order declaration in command will be omitted
    ASC,
    ASC_NULLS_FIRST,
    ASC_NULLS_LAST,
    DESC,
    DESC_NULLS_FIRST,
    DESC_NULLS_LAST,
}

@Target({})
@Retention(RUNTIME)
public @interface Col { // Specifies column in other annotations
    String name();
    SortOrder sort() default SortOrder.DEFAULT;
}

@Target({})
@Retention(RUNTIME)
public @interface Index {
    String name() default "";
    Col[] columns();
    IndexType type() default IndexType.DEFAULT;
}

public enum IndexType {
    TREE, HASH, 
    DEFAULT // index type declaration in command will be omitted
}

@Target({})
@Retention(RUNTIME)
public @interface ColocateBy {
    Col[] columns();
}

@Target(FIELD)
@Retention(RUNTIME)
public @interface Id {
    SortOrder sort() default SortOrder.DEFAULT; // order declaration will be omitted
}

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Column {
    String name() default "";
    boolean nullable() default true;
    int length() default -1;
    int precision() default -1;
    int scale() default -1;
    String columnDefinition() default "";
}

@Target(TYPE)
@Retention(RUNTIME)
public @interface Zone {
    String name();
    int partitions() default -1;
    int replicas() default -1;
    int dataNodesAutoAdjust() default -1;
    int dataNodesAutoAdjustScaleUp() default -1;
    int dataNodesAutoAdjustScaleDown() default -1;
    String filter() default "";
    ZoneEngine engine() default ZoneEngine.DEFAULT;
    String dataregion() default "";
}

public enum ZoneEngine {
    AIMEM, ROCKSDB, 
    DEFAULT // zone engine declaration in dll will be omitted
}


Examples


// kvView example

@Zone(
        name = "zone_test",
        partitions = 2,
        engine = ZoneEngine.ROCKSDB
)
class ZoneTest {}

class PojoKey {
    @Id
    Integer id;
    
    @Id(sort = DESC)
    @Column(name = "id_str", length = 20)
    String idStr;
}

@Table(
    name = "kv_pojo_test",
        zone = ZoneTest.class,
        colocateBy = @ColocateBy(columns = {
                    @Col(name = "f_name"),
                    @Col(name = "l_name") }),
    indexes = { @Index(name = "ix_test", columns = {
@Col(name = "f_name"), 
                    @Col(name = "l_name", sort = DESC_NULLS_LAST) })
    }
)
class PojoValue {
    @Column(name = "f_name")
    String firstName;

    @Column(name = "l_name")
    String lastName;

    String str;
}

// execute to create table
ignite.catalog().create(PojoKey.class, PojoValue.class).execute();

// example defining KV pojo, compatible with keyValueView
ignite.tables().table("kv_pojo_test").keyValueView(PojoKey.class, PojoValue.class)

// is equivalent to multi-statement
CREATE ZONE IF NOT EXISTS zone_test ENGINE ROCKSDB WITH PARTITIONS=2;

CREATE TABLE IF NOT EXISTS kv_pojo_test (
    id int,
    id_str varchar(20),
    f_name varchar,
    l_name varchar,
    str varchar,
    PRIMARY KEY (id, id_str desc)
)
COLOCATE BY (f_name, l_name)
WITH PRIMARY_ZONE='ZONE_TEST';

CREATE INDEX ix_test (f_name, l_name desc nulls last);



// recordView example
@Table(
        name = "pojo_test",
        zone = ZoneTest.class,
        colocateBy = @ColocateBy(columns = {
                @Col(name = "f_name"),
                @Col(name = "l_name") }),
        indexes = {
                @Index(name = "ix_test", columns = {
                        @Col(name = "f_name"),
                        @Col(name = "l_name", sort = DESC_NULLS_LAST)
                    }
                }
                )
class Pojo {
    @Id
    Integer id;
    
    @Id(sort = DESC)
    @Column(name = "id_str", length = 20)
    String idStr;
    
    @Column(name = "f_name")
    String firstName;
    
    @Column(name = "l_name")
    String lastName;
    
    String str;
}

// execute to create table
ignite.catalog().create(Pojo.class).execute();

// example defining single pojo, compatible with recordView
ignite.tables().table("kv_pojo_test").recordView(Pojo.class)



// example of using builder alternative to @Table annotation

class Pojo {
    @Id
        Integer id;

    @Id(sort = DESC)
    @Column(name = "id_str", length = 20)
    String idStr;

    @Column(name = "f_name")
    String firstName;

    @Column(name = "l_name")
    String lastName;

    String str;
}

ignite.catalog()
  .create(ZoneDefinition.builder("zone_test")
        .partitions(2))
  .execute();

ignite.catalog()
  .create(TableDefinition.builder("pojo_test")
        .ifNotExists()
        .colocateBy("id", "id_str")
        .zone("zone_test")
        .recordView(Pojo.class) // .keyValueView(Key.class, Value.class)
        .build())
  .execute();


Risks and Assumptions

No any risks

Reference Links

[AI2 Query Entities](https://ignite.apache.org/docs/latest/SQL/indexes

Tickets

- [AI3 Epic IGNITE-21410]( IGNITE-21410 - Getting issue details... STATUS )

  • No labels