contente
Plugin de código aberto Tapdata PDK
Acesso rápido ao banco de dados de destino
Baixe o código fonte e compile
Crie um projeto do Connector para o banco de dados de destino
Teste e verifique através do TDD após a conclusão do desenvolvimento
Como enviar para o projeto de código aberto PDK
Introdução:
Não é exagero dizer que não há desenvolvedor que ainda não tenha chutado a placa de ferro da "não interoperabilidade de dados de aplicativos" - no caso de diferentes plataformas, diferentes tecnologias, diferentes métodos de armazenamento e implantação e a falta de interfaces, os sistemas de aplicação são diferentes, de difícil comunicação. Com a contínua expansão dos requisitos de negócios, os aplicativos estão em constante desenvolvimento para diversificação e personalização.A contradição entre negócios futuros e pilhas de tecnologia desatualizadas também está se tornando cada vez mais proeminente, e o número de interfaces necessárias também está aumentando.
Como tornar o desenvolvimento da interface simples e rápido tornou-se um problema que precisamos considerar. Recentemente, desenterrei um plug-in de código aberto muito perfumado. Depois de estudar cuidadosamente a documentação técnica, decidi dar a você a Amway:
Plugin de código aberto Tapdata PDK
Link do GitHub: https://github.com/tapdata/idaas-pdk
A editora deste projeto é a Tapdata, uma equipe empresarial nacional especializada em plataformas de serviços de dados em tempo real. Segundo os funcionários, esse componente de código aberto também é o trampolim para o código aberto de seus principais produtos. sincronização de dados de tempo.Uma força bastante madura.
PDK é uma estrutura de desenvolvimento de plug-in de código aberto abstraída de sua tecnologia de interface de dados. Através da interface Source Plugin ou da interface Target Plugin, a adaptação e compatibilidade do novo banco de dados como origem ou destino do Tapdata podem ser realizadas rapidamente, de modo que o produto Tapdata Cloud e o próximo código aberto podem ser realizados rapidamente Tapdata várias fontes de dados heterogêneas para bancos de dados ou plataformas de destino.
De acordo com a especificação de desenvolvimento do conector PDK, o desenvolvimento de fonte e destino de dados pode simplificar o processo de desenvolvimento de link de dados. .
Os tipos de suporte incluem:
- Banco de dados de acesso: MySQL, Oracle, PostgreSQL, etc.
- Acesse produtos SaaS : Salesforce, vika table, gold data form, Zoho CRM, etc.
- Acesso a fontes de dados personalizadas: pode se conectar a fontes de dados de protocolo privado
Acesso rápido ao banco de dados de destino
Atualmente, a equipe do PDK tornou públicos os documentos técnicos e você pode acessar o GitHub ( https://github.com/tapdata/idaas-pdk ) para obter detalhes.
Prepare o ambiente
- Java8
- Especialista
- Git
- INtelliJ IDEA
Baixe o código fonte e compile
git clone https://github.com/tapdata/idaas-pdk.git
cd idaas-pdk
mvn clean install
Crie um projeto do Connector para o banco de dados de destino
Por exemplo, o grupo é io.tapdata, o nome do banco de dados é XDB e a versão da versão é 0.0.1. Crie um projeto Connector com o seguinte comando
-
Quando o banco de dados de destino não precisa criar uma tabela
./bin/tap template --type target --group io.tapdata --name XDB --version 0.0.1 --output ./connectors
Abra o idaas-pdk com o ItelliJ IDEA e você poderá ver o projeto xdb-connector em idaas-pdk/connectors.
- Preencha configOptions em spec.json
Após o configOptions ser integrado ao site Tapdata, ele configura os itens de entrada para o usuário ao utilizar o Conector, como endereço de conexão do banco de dados, nome de usuário, senha, etc.
{
...
"configOptions":{
"connection":{
"type":"object",
"properties":{
"host":{
"type": "string",
"title": "Host",
"x-decorator": "FormItem",
"x-component": "Input"
},
"port":{
"type": "number",
"title": "Port",
"x-decorator": "FormItem",
"x-component": "Input"
}
}
}
}
}
- Escreva o código para acessar o banco de dados de destino
@TapConnectorClass("spec.json")
public class XDBConnector extends ConnectorBase implements TapConnector {
@Override
public void discoverSchema(TapConnectionContext connectionContext, Consumer<List<TapTable>> consumer) {
//TODO Load tables from database, connection information in connectionContext#getConnectionConfig
//Sample code shows how to define tables.
consumer.accept(list(
//Define first table
table("empty-table1"),
//Define second table
table("empty-table2"))
));
}
@Override
public void connectionTest(TapConnectionContext connectionContext, Consumer<TestItem> consumer) {
//Assume below tests are successfully, below tests are recommended, but not required.
//Connection test
//TODO execute connection test here
consumer.accept(testItem(TestItem.ITEM_CONNECTION, TestItem.RESULT_SUCCESSFULLY));
//Login test
//TODO execute login test here
consumer.accept(testItem(TestItem.ITEM_LOGIN, TestItem.RESULT_SUCCESSFULLY));
//Read test
//TODO execute read test by checking role permission
consumer.accept(testItem(TestItem.ITEM_READ, TestItem.RESULT_SUCCESSFULLY));
//Write test
//TODO execute write test by checking role permission
consumer.accept(testItem(TestItem.ITEM_WRITE, TestItem.RESULT_SUCCESSFULLY));
}
private void writeRecord(TapConnectorContext connectorContext, List<TapRecordEvent> tapRecordEvents, Consumer<WriteListResult<TapRecordEvent>> writeListResultConsumer) {
//TODO write records into database
//Below is sample code to print received events which suppose to write to database.
AtomicLong inserted = new AtomicLong(0); //insert count
AtomicLong updated = new AtomicLong(0); //update count
AtomicLong deleted = new AtomicLong(0); //delete count
for(TapRecordEvent recordEvent : tapRecordEvents) {
if(recordEvent instanceof TapInsertRecordEvent) {
//TODO insert record
inserted.incrementAndGet();
} else if(recordEvent instanceof TapUpdateRecordEvent) {
//TODO update record
updated.incrementAndGet();
} else if(recordEvent instanceof TapDeleteRecordEvent) {
//TODO delete record
deleted.incrementAndGet();
}
}
//Need to tell incremental engine the write result
writeListResultConsumer.accept(writeListResult()
.insertedCount(inserted.get())
.modifiedCount(updated.get())
.removedCount(deleted.get()));
}
private void queryByFilter(TapConnectorContext connectorContext, List<TapFilter> filters, Consumer<List<FilterResult>> listConsumer){
//Filter is exactly match.
//If query by the filter, no value is in database, please still create a FitlerResult with null value in it. So that flow engine can understand the filter has no value.
}
}
-
Quando o banco de dados de destino precisa criar uma tabela
./bin/tap template --type targetNeedTable --group io.tapdata --name XDB --version 0.0.1 --output ./connectors
Abra o idaas-pdk com o ItelliJ IDEA e você poderá ver o projeto xdb-connector em idaas-pdk/connectors.
- Preencha configOptions em spec.json
Depois que o configOptions estiver integrado ao site Tapdata, configure os itens de entrada para o usuário ao usar o Conector, como endereço de conexão do banco de dados, nome de usuário, senha, etc.
{
...
"configOptions":{
"connection":{
"type":"object",
"properties":{
"host":{
"type": "string",
"title": "Host",
"x-decorator": "FormItem",
"x-component": "Input"
},
"port":{
"type": "number",
"title": "Port",
"x-decorator": "FormItem",
"x-component": "Input"
}
}
}
}
}
- Preencha dataTypes (expressão de tipo) em spec.json
dataTypes é usado para descrever o intervalo de todos os campos que este Conector acessa o banco de dados e converte no TapType correspondente. O banco de dados de origem também fornecerá a mesma descrição de dataTypes, portanto, quando os dados de origem fluirem para Tapdata, ele combinará as informações de descrição de campo dos dataTypes de origem com as informações de campo da tabela de banco de dados de origem e inserirá Tapdata por meio da estrutura de dados neutra de Tapdata. No fluxo de dados, antes que os dados fluam para o banco de dados de destino, o Tapdata encontrará o melhor campo de armazenamento nos dataTypes da biblioteca de destino com base nessas informações e informará o desenvolvedor do PDK por meio do originType do TapField para construir a tabela .
{
...
"dataTypes":{
"boolean":{"bit":8, "unsigned":"", "to":"TapNumber"},
"tinyint":{"bit":8, "to":"TapNumber"},
"smallint":{"bit":16, "to":"TapNumber"},
"int":{"bit":32, "to":"TapNumber"},
"bigint":{"bit":64, "to":"TapNumber"},
"largeint":{"bit":128, "to":"TapNumber"},
"float":{"bit":32, "to":"TapNumber"},
"double":{"bit":64, "to":"TapNumber"},
"decimal[($precision,$scale)]":{"bit": 128, "precision": [1, 27], "defaultPrecision": 10, "scale": [0, 9], "defaultScale": 0, "to": "TapNumber"},
"date":{"byte":3, "range":["0000-01-01", "9999-12-31"], "to":"TapDate"},
"datetime":{"byte":8, "range":["0000-01-01 00:00:00","9999-12-31 23:59:59"],"to":"TapDateTime"},
"char[($byte)]":{"byte":255, "to": "TapString", "defaultByte": 1},
"varchar[($byte)]":{"byte":"65535", "to":"TapString"},
"string":{"byte":"2147483643", "to":"TapString"},
"HLL":{"byte":"16385", "to":"TapNumber", "queryOnly":true}
}
}
- Escreva o código para acessar o banco de dados de destino
@TapConnectorClass("spec.json")
public class XDBConnector extends ConnectorBase implements TapConnector {
@Override
public void discoverSchema(TapConnectionContext connectionContext, Consumer<List<TapTable>> consumer) {
//TODO Load schema from database, connection information in connectionContext#getConnectionConfig
//Sample code shows how to define tables with specified fields
consumer.accept(list(
//Define first table
table("empty-table1")
//Define a field named "id", origin field type, whether is primary key and primary key position
.add(field("id", "varchar").isPrimaryKey(true).partitionKeyPos(1))
.add(field("description", "string"))
.add(field("name", "varchar"))
.add(field("age", "int")))
));
}
@Override
public void connectionTest(TapConnectionContext connectionContext, Consumer<TestItem> consumer) {
//Assume below tests are successfully, below tests are recommended, but not required.
//Connection test
//TODO execute connection test here
consumer.accept(testItem(TestItem.ITEM_CONNECTION, TestItem.RESULT_SUCCESSFULLY));
//Login test
//TODO execute login test here
consumer.accept(testItem(TestItem.ITEM_LOGIN, TestItem.RESULT_SUCCESSFULLY));
//Read test
//TODO execute read test by checking role permission
consumer.accept(testItem(TestItem.ITEM_READ, TestItem.RESULT_SUCCESSFULLY));
//Write test
//TODO execute write test by checking role permission
consumer.accept(testItem(TestItem.ITEM_WRITE, TestItem.RESULT_SUCCESSFULLY));
}
@Override
public void registerCapabilities(ConnectorFunctions connectorFunctions, TapCodecRegistry codecRegistry) {
connectorFunctions.supportWriteRecord(this::writeRecord);
connectorFunctions.supportQueryByFilter(this::queryByFilter);
//If database need insert record before table created, then please implement the below two methods.
connectorFunctions.supportCreateTable(this::createTable);
connectorFunctions.supportDropTable(this::dropTable);
//If database need insert record before table created, please implement the custom codec for the TapValue that data types in spec.json didn't cover.
//TapTimeValue, TapMapValue, TapDateValue, TapArrayValue, TapYearValue, TapNumberValue, TapBooleanValue, TapDateTimeValue, TapBinaryValue, TapRawValue, TapStringValue
codecRegistry.registerFromTapValue(TapRawValue.class, "text", tapRawValue -> {
if (tapRawValue != null && tapRawValue.getValue() != null)
return toJson(tapRawValue.getValue());
return "null";
});
}
private void writeRecord(TapConnectorContext connectorContext, List<TapRecordEvent> tapRecordEvents, Consumer<WriteListResult<TapRecordEvent>> writeListResultConsumer) {
//TODO write records into database
//Below is sample code to print received events which suppose to write to database.
AtomicLong inserted = new AtomicLong(0); //insert count
AtomicLong updated = new AtomicLong(0); //update count
AtomicLong deleted = new AtomicLong(0); //delete count
for(TapRecordEvent recordEvent : tapRecordEvents) {
if(recordEvent instanceof TapInsertRecordEvent) {
//TODO insert record
inserted.incrementAndGet();
PDKLogger.info(TAG, "Record Write TapInsertRecordEvent {}", toJson(recordEvent));
} else if(recordEvent instanceof TapUpdateRecordEvent) {
//TODO update record
updated.incrementAndGet();
PDKLogger.info(TAG, "Record Write TapUpdateRecordEvent {}", toJson(recordEvent));
} else if(recordEvent instanceof TapDeleteRecordEvent) {
//TODO delete record
deleted.incrementAndGet();
PDKLogger.info(TAG, "Record Write TapDeleteRecordEvent {}", toJson(recordEvent));
}
}
//Need to tell incremental engine the write result
writeListResultConsumer.accept(writeListResult()
.insertedCount(inserted.get())
.modifiedCount(updated.get())
.removedCount(deleted.get()));
}
private void queryByFilter(TapConnectorContext connectorContext, List<TapFilter> filters, Consumer<List<FilterResult>> listConsumer){
//Filter is exactly match.
//If query by the filter, no value is in database, please still create a FitlerResult with null value in it. So that flow engine can understand the filter has no value.
}
private void dropTable(TapConnectorContext connectorContext, TapDropTableEvent dropTableEvent) {
TapTable table = connectorContext.getTable();
//TODO implement drop table
}
private void createTable(TapConnectorContext connectorContext, TapCreateTableEvent createTableEvent) {
//TODO implement create table.
TapTable table = connectorContext.getTable();
LinkedHashMap<String, TapField> nameFieldMap = table.getNameFieldMap();
for(Map.Entry<String, TapField> entry : nameFieldMap.entrySet()) {
TapField field = entry.getValue();
String originType = field.getOriginType();
//originType is the data types defined in spec.json
//TODO use the generated originType to create table.
}
}
}
Teste e verifique através do TDD após a conclusão do desenvolvimento
Forneça um arquivo json que precisa ser preenchido pelo usuário em configOptions. Por exemplo, no configOptions acima, o usuário deve preencher o Host e a Porta do banco de dados, depois o conteúdo do arquivo xdb_tdd.json do tdd é o seguinte:
{
"connection": {
"host": "192.168.153.132",
"port": 9030,
}
}
Execute o comando de teste TDD:
./bin/tap tdd --testConfig xdb_tdd.json ./connectors/xdb-connector
Quando o teste TDD falhar, modifique os erros correspondentes de acordo com os prompts de erro até que o teste TDD seja aprovado;
Quando o teste TDD for aprovado, o PDK Connector estará em um estado em que uma solicitação de pull pode ser enviada.
Como enviar para o projeto de código aberto PDK
① fork idaas-pdk, crie um branch local baseado no branch principal remoto
② De acordo com o nome do banco de dados a ser acessado, crie um novo módulo no diretório idaas-pdk/connectors, e a convenção de nomenclatura é {database lowercase name}-connector, por exemplo, o nome do banco de dados de acesso é XDB, e o nome do módulo é conector xdb
③ O desenvolvedor conclui o desenvolvimento e implementação do banco de dados de acesso de acordo com o documento oficial da API
④ Depois de passar no teste TDD, envie PR para idaas-pdk
⑤ Mesclar o código após o PR enviado pela equipe oficial Revisão
ovos de Páscoa
Os alunos interessados não se apressam em desenvolvê-lo. Entende-se que a versão oficial gratuita realizou sucessivamente conexão de dados em tempo real entre 30 fontes/destinos de dados comuns. Se já contém o banco de dados que você deseja acessar, você pode usar Tapdata Cloud diretamente ( Tapdata Cloud | Free Heterogeneneous Database Real-time Sync Cloud Platform - Tapdata ) para sincronização gratuita de dados em tempo real. Obviamente, se suas necessidades não forem atendidas neste estágio, você poderá usar o Tapdata PDK para desenvolvimento de autoatendimento e acesso rápido.
Tipos de conexão de dados atualmente suportados pelo Tapdata Cloud
Atualmente, a Tapdata abriu um grupo de co-construção ecológica de plug-ins para desenvolvedores. Ele pode fornecer trocas técnicas e suporte durante o processo de desenvolvimento. Os alunos interessados podem digitalizar o código a seguir e convidá-lo a participar do grupo: