コンテンツ
序章:
さまざまなプラットフォーム、さまざまなテクノロジー、さまざまなストレージと展開方法、および必要性の欠如の場合、「アプリケーションデータの非相互運用性」の鉄板をまだ蹴っていない開発者はいないと言っても過言ではありません。インターフェイス、アプリケーションシステムが異なります。通信が困難です。ビジネス要件の継続的な拡大に伴い、アプリケーションは多様化とパーソナライズに向けて絶えず開発されています。将来のビジネスと古いテクノロジースタックとの矛盾もますます顕著になり、必要なインターフェイスの数も増えています。
インターフェイス開発をシンプルかつ迅速に行う方法は、私たちが検討する必要のある問題になっています。最近、私は非常に香りのよいオープンソースプラグインを掘り起こしました。技術文書を注意深く検討した後、アムウェイに提供することにしました。
オープンソースプラグインTapdataPDK
GitHubリンク:https ://github.com/tapdata/idaas-pdk
このプロジェクトの発行元は、リアルタイムデータサービスプラットフォームを専門とする国内の起業家チームであるTapdataです。関係者によると、このオープンソースコンポーネントは、コア製品のオープンソースの足がかりでもあります。チームの本物に支えられています。 -時間データの同期。かなり成熟した強み。
PDKは、データインターフェイステクノロジーから抽象化されたオープンソースプラグイン開発フレームワークです。ソースプラグインインターフェイスまたはターゲットプラグインインターフェイスを介して、Tapdataのソースまたはターゲットとしての新しいデータベースの適応と互換性を迅速に実現できるため、Tapdata Cloud製品と今後の オープンソースを迅速に実現できます。Tapdata、さまざまな異種データソースからターゲットデータベースまたはプラットフォームへのリアルタイムデータドッキング機能への無料アクセス 。
PDKコネクタの開発仕様によると、データソースとターゲットの開発により、データリンクの開発プロセスを簡素化できます。詳細な開発計画と組み込みのTDDテストにより、新しいデータソースとターゲットの開発を簡単かつ迅速に完了できます。 。
サポートの種類は次のとおりです。
- アクセスデータベース: MySQL、Oracle、PostgreSQLなど。
- SaaS 製品へのアクセス: Salesforce、vikaテーブル、ゴールドデータフォーム、ZohoCRMなど。
- カスタムデータソースへのアクセス: プライベートプロトコルデータソースに接続できます
クイックスタートターゲットデータベースアクセス
現在、PDKチームは技術文書を公開しています。詳細については、GitHub(https://github.com/tapdata/idaas-pdk) にアクセスしてください。
環境を整える
- Java 8
- Maven
- ギット
- IntelliJ IDEA
ソースコードをダウンロードしてコンパイルする
git clone https://github.com/tapdata/idaas-pdk.git
cd idaas-pdk
mvn clean install
ターゲットデータベースのコネクタプロジェクトを作成します
たとえば、グループはio.tapdata、データベース名はXDB、バージョンバージョンは0.0.1です。次のコマンドを使用してコネクタプロジェクトを作成します。
-
ターゲットデータベースがテーブルを作成する必要がない場合
./bin/tap template --type target --group io.tapdata --name XDB --version 0.0.1 --output ./connectors
ItelliJ IDEAでidaas-pdkを開くと、idaas-pdk/connectorsの下にxdb-connectorプロジェクトが表示されます。
- spec.jsonにconfigOptionsを入力します
configOptionsがTapdataサイトに統合された後、データベース接続アドレス、ユーザー名、パスワードなど、コネクターを使用する際のユーザーの入力項目を構成します。
{
...
"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"
}
}
}
}
}
- ターゲットデータベースにアクセスするためのコードを記述します
@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.
}
}
-
ターゲットデータベースがテーブルを作成する必要がある場合
./bin/tap template --type targetNeedTable --group io.tapdata --name XDB --version 0.0.1 --output ./connectors
ItelliJ IDEAでidaas-pdkを開くと、idaas-pdk/connectorsの下にxdb-connectorプロジェクトが表示されます。
- spec.jsonにconfigOptionsを入力します
configOptionsがTapdataサイトに統合された後、データベース接続アドレス、ユーザー名、パスワードなど、コネクターを使用する際のユーザーの入力項目を構成します。
{
...
"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"
}
}
}
}
}
- spec.jsonにdataTypes(型式)を入力します
dataTypesは、このコネクタがデータベースにアクセスし、対応するTapTypeに変換するすべてのフィールドの範囲を記述するために使用されます。ソースデータベースも同じdataTypes記述を提供するため、ソースデータがTapdataに流入すると、ソースdataTypesのフィールド記述情報とソースデータベーステーブルのフィールド情報が結合され、のニュートラルデータ構造を介してTapdataが入力されます。 Tapdata。データフローでは、データがターゲットデータベースに流れる前に、Tapdataはこの情報に基づいてターゲットライブラリのdataTypesで最適なストレージフィールドを見つけ、TapFieldのoriginTypeを介してPDK開発者にテーブルを作成するよう通知します。 。
{
...
"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}
}
}
- ターゲットデータベースにアクセスするためのコードを記述します
@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.
}
}
}
開発が完了した後、TDDを介してテストおよび検証します
configOptionsにユーザーが入力する必要のあるjsonファイルを提供します。たとえば、上記のconfigOptionsでは、ユーザーはデータベースのホストとポートを入力してから、tddのxdb_tdd.jsonファイルの内容を入力する必要があります。以下のとおりであります:
{
"connection": {
"host": "192.168.153.132",
"port": 9030,
}
}
TDDテストコマンドを実行します。
./bin/tap tdd --testConfig xdb_tdd.json ./connectors/xdb-connector
TDDテストが失敗した場合は、TDDテストに合格するまで、エラープロンプトに従って対応するエラーを変更してください。
TDDテストに合格すると、PDKコネクタはプルリクエストを送信できる状態になります。
PDKオープンソースプロジェクトに提出する方法
①forkidaas-pdk、リモートメインブランチに基づいてローカルブランチを作成します
②アクセスするデータベースの名前に応じて、idaas-pdk / connectedorsディレクトリに新しいモジュールを作成します。命名規則は{データベース小文字名}-コネクタです。たとえば、アクセスデータベースの名前はXDBです。モジュール名はxdb-connectorです。
③開発者は、公式APIドキュメントに従ってアクセスデータベースの開発と実装を完了します
④TDDテストに合格したら、PRをidaas-pdkに提出してください
⑤公式チームレビューで提出されたPR後にコードをマージする
イースターエッグ
興味のある学生は急いで開発する必要はありません。公式の無料バージョンでは、30の一般的なデータソース/ターゲット間のリアルタイムデータ接続が連続して実現されていることがわかります。アクセスしたいデータベースがすでに含まれている場合は、TapdataCloudを使用できます。直接(Tapdata Cloud |無料の異種データベースリアルタイム同期クラウドプラットフォーム-Tapdata)、無料のリアルタイムデータ同期を実現します。もちろん、この段階でニーズがサポートされていない場合は、TapdataPDKを使用してセルフサービス開発と迅速なアクセスを行うことができます。
TapdataCloudで現在サポートされているデータ接続タイプ
現在、Tapdataは、開発者向けのプラグインエコロジカル共同構築グループを開設しました。開発プロセス中に技術的な交換とサポートを提供できます。興味のある学生は、コードをスキャンしてフォローし、グループに参加するよう招待できます。