tamuです。

Heroku Connectを使った際のローカルでの開発について調査しました。 常にHerokuにデプロイして動作確認をするのは実行コストがかかるので、 ローカルのPostgreSQLにHeroku Connect同等のスキーマを用意する手順をまとめました。

Heroku Connect の接続

前回記事を参考に、Heroku Connectを使ってSalesforceのレコードをPostgreSQLで参照できるようにします。

Salesforceスキーマのダンプ

pg_dump を使い、Salesforceスキーマをダンプします。

その前にHeroku PostgreSQLへの接続情報を取得します。

Heroku PostgreSQLの接続情報の取得

heroku pg:credentials:url でHeroku PostgreSQLへの接続情報を取得することができます。

1
2
3
4
5
6
$ heroku pg:credentials:url -a <app-name>
Connection information for default credential.
Connection info string:
   "dbname=xxxxxxxxxxxxxx host=ec2-xx-xx-xx-xx.xxxxxxxxxx.amazonaws.com port=xxxx user=xxxxxxxxxxxxxx password=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx sslmode=require"
Connection URL:
   postgres://xxxxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@ec2-xx-xx-xx-xx.xxxxxxxxxx.amazonaws.com:xxxx/xxxxxxxxxxxxxx

いったんはここまでで大丈夫です。

ここからは単なるテストです。 この情報を使って psql で接続できるかやってみます。

1
2
3
4
5
psql -U <ユーザ名> -h <ホスト名> -p <ポート番号> -W <データベース名>
Password:
psql (13.3, server 13.4 (Ubuntu 13.4-1.pgdg20.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

接続できたようです。 データも参照できるかやってみます。

1
2
3
4
5
xxxxxxxxxxx=> select * from salesforce.product2;
 externalproductid__c | family | externalid |   lastvieweddate    | stockkeepingunit |               name                | externaldatasourceid | displayurl |  lastmodifieddate   | isdeleted | isactive |   systemmodstamp    |  lastmodifiedbyid  |     createddate     | quantityunitofmeasure |    createdbyid     |    productcode    | description | lastreferenceddate  |        sfid        | id | _hc_lastop | _hc_err
----------------------+--------+------------+---------------------+------------------+-----------------------------------+----------------------+------------+---------------------+-----------+----------+---------------------+--------------------+---------------------+-----------------------+--------------------+-------------------+-------------+---------------------+--------------------+----+------------+---------
 PRODUCT_TEST_0000    |        |            | 2021-07-25 08:53:39 |                  | テスト                            |                      |            | 2021-07-25 08:52:10 | f         | f        | 2021-07-25 08:52:10 | 0055h000003CqwWAAS | 2021-07-25 08:52:10 |                       | 0055h000003CqwWAAS | PRODUCT_TEST_0000 | テストです  | 2021-07-25 08:53:39 | 01t5h000000AzOHAA0 | 20 | SYNCED     |
(1 row)

前回と同じデータが取れました。

スキーマ情報のダンプ

pg_dump を使ってスキーマ情報をダンプします。

1
$ pg_dump -d <データベース名> -h <ホスト名> -U <ユーザ名> --schema-only -t 'salesforce.*'  -W > dump.sql

この中にある salesforce.product2 に関連するSQLを抽出してきます。 (トリガ処理は除外しています)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
CREATE TABLE salesforce.product2 (
    externalproductid__c character varying(255),
    family character varying(255),
    externalid character varying(255),
    lastvieweddate timestamp without time zone,
    stockkeepingunit character varying(180),
    name character varying(255),
    externaldatasourceid character varying(18),
    displayurl character varying(1000),
    lastmodifieddate timestamp without time zone,
    isdeleted boolean,
    isactive boolean,
    systemmodstamp timestamp without time zone,
    lastmodifiedbyid character varying(18),
    createddate timestamp without time zone,
    quantityunitofmeasure character varying(255),
    createdbyid character varying(18),
    productcode character varying(255),
    description character varying(4000),
    lastreferenceddate timestamp without time zone,
    sfid character varying(18) COLLATE pg_catalog.ucs_basic,
    id integer NOT NULL,
    _hc_lastop character varying(32),
    _hc_err text
);

CREATE SEQUENCE salesforce.product2_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

ALTER SEQUENCE salesforce.product2_id_seq OWNED BY salesforce.product2.id;

ALTER TABLE ONLY salesforce.product2 ALTER COLUMN id SET DEFAULT nextval('salesforce.product2_id_seq'::regclass);

ALTER TABLE ONLY salesforce.product2
    ADD CONSTRAINT product2_pkey PRIMARY KEY (id);

CREATE INDEX hc_idx_product2_lastmodifieddate ON salesforce.product2 USING btree (lastmodifieddate);

CREATE INDEX hc_idx_product2_systemmodstamp ON salesforce.product2 USING btree (systemmodstamp);

CREATE UNIQUE INDEX hcu_idx_product2_externalproductid__c ON salesforce.product2 USING btree (externalproductid__c);

CREATE UNIQUE INDEX hcu_idx_product2_sfid ON salesforce.product2 USING btree (sfid);

これを 2.sql のような名前をつけて保存しておきます。

1.sql は後述

ローカル環境の準備

ローカルはdockerで環境を作ると色々と楽なのでdockerで準備していきます。

docker-compose.yml の作成

ポイントは herokuconnect ディレクトリを用意して、起動時にその中にあるSQLファイルを実行できるようにしてある点です。 こうすることで、Heroku Connect先(Salesforce側)のスキーマを事前に定義することができます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
version: "3"
services:
  dbserver:
    image: postgres:12
    container_name: herokuconndb
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: password
      POSTGRES_DB: herokuconn
      POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
    volumes:
      - database:/var/lib/postgresql/data
      - ./herokuconnect:/docker-entrypoint-initdb.d
volumes:
  database:
    driver: local

起動時SQLの準備

salesforce スキーマをつくる 1.sql というSQLを用意します。

1
CREATE SCHEMA salesforce;

この他、上で作った 2.sql を用意し、 herokuconnect ディレクトリに放り込んでおきます。

ローカルのデータベースの起動

docker compose up でPostgreSQLを起動します。 起動すると herokuconnect ディレクトリにあるSQLファイルを順番に読み込み、実行してくれます。

...
herokuconndb  | server started
herokuconndb  | CREATE DATABASE
herokuconndb  |
herokuconndb  |
herokuconndb  | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/1.sql
herokuconndb  | CREATE SCHEMA
herokuconndb  |
herokuconndb  |
herokuconndb  | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/2.sql
herokuconndb  | CREATE TABLE
herokuconndb  | CREATE SEQUENCE
herokuconndb  | ALTER SEQUENCE
herokuconndb  | ALTER TABLE
herokuconndb  | ALTER TABLE
herokuconndb  | CREATE INDEX
herokuconndb  | CREATE INDEX
herokuconndb  | CREATE INDEX
herokuconndb  | CREATE INDEX
herokuconndb  |
...

psql でつないでスキーマができているか確認してみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$ psql -U root -h 127.0.0.1 -W herokuconn
Password:
psql (13.3, server 12.8 (Debian 12.8-1.pgdg100+1))
Type "help" for help.

herokuconn=# \d salesforce.product2
                                                 Table "salesforce.product2"
        Column         |            Type             | Collation | Nullable |                     Default
-----------------------+-----------------------------+-----------+----------+-------------------------------------------------
 externalproductid__c  | character varying(255)      |           |          |
 family                | character varying(255)      |           |          |
 externalid            | character varying(255)      |           |          |
 lastvieweddate        | timestamp without time zone |           |          |
 stockkeepingunit      | character varying(180)      |           |          |
 name                  | character varying(255)      |           |          |
 externaldatasourceid  | character varying(18)       |           |          |
 displayurl            | character varying(1000)     |           |          |
 lastmodifieddate      | timestamp without time zone |           |          |
 isdeleted             | boolean                     |           |          |
 isactive              | boolean                     |           |          |
 systemmodstamp        | timestamp without time zone |           |          |
 lastmodifiedbyid      | character varying(18)       |           |          |
 createddate           | timestamp without time zone |           |          |
 quantityunitofmeasure | character varying(255)      |           |          |
 createdbyid           | character varying(18)       |           |          |
 productcode           | character varying(255)      |           |          |
 description           | character varying(4000)     |           |          |
 lastreferenceddate    | timestamp without time zone |           |          |
 sfid                  | character varying(18)       | ucs_basic |          |
 id                    | integer                     |           | not null | nextval('salesforce.product2_id_seq'::regclass)
 _hc_lastop            | character varying(32)       |           |          |
 _hc_err               | text                        |           |          |
Indexes:
    "product2_pkey" PRIMARY KEY, btree (id)
    "hc_idx_product2_lastmodifieddate" btree (lastmodifieddate)
    "hc_idx_product2_systemmodstamp" btree (systemmodstamp)
    "hcu_idx_product2_externalproductid__c" UNIQUE, btree (externalproductid__c)
    "hcu_idx_product2_sfid" UNIQUE, btree (sfid)

無事、salesforce.product2 スキーマが作成されていました。

まとめ

  • Heroku PostgreSQLは heroku pg:credentials:url で接続情報を取得できる
  • Heroku Connectでつながった先のSalesforceのスキーマは pg_dump で取得する
  • 取得したスキーマを使ってローカル環境にスキーマを再現することができる