From 41c9707f26a4a83091d13db7cafe5ea61abe9174 Mon Sep 17 00:00:00 2001 From: Evan Corkrean <62527488+corkrean@users.noreply.github.com> Date: Tue, 18 Feb 2025 14:17:01 -0700 Subject: [PATCH 1/6] adding materialize demo --- .../authzed-download-fbc717.yaml | 29 +++ code-examples/go/materialize-demo/cleanup.sh | 17 ++ code-examples/go/materialize-demo/go.mod | 45 ++++ code-examples/go/materialize-demo/go.sum | 198 ++++++++++++++++++ .../go/materialize-demo/internal/data/load.go | 71 +++++++ .../internal/data/postgres_init.go | 153 ++++++++++++++ .../go/materialize-demo/internal/data/read.go | 143 +++++++++++++ .../materialize-demo/internal/spice/spice.go | 121 +++++++++++ .../materialize-demo/internal/tiger/tiger.go | 106 ++++++++++ code-examples/go/materialize-demo/main.go | 134 ++++++++++++ code-examples/go/materialize-demo/readme.MD | 11 + 11 files changed, 1028 insertions(+) create mode 100644 code-examples/go/materialize-demo/authzed-download-fbc717.yaml create mode 100755 code-examples/go/materialize-demo/cleanup.sh create mode 100644 code-examples/go/materialize-demo/go.mod create mode 100644 code-examples/go/materialize-demo/go.sum create mode 100644 code-examples/go/materialize-demo/internal/data/load.go create mode 100644 code-examples/go/materialize-demo/internal/data/postgres_init.go create mode 100644 code-examples/go/materialize-demo/internal/data/read.go create mode 100644 code-examples/go/materialize-demo/internal/spice/spice.go create mode 100644 code-examples/go/materialize-demo/internal/tiger/tiger.go create mode 100644 code-examples/go/materialize-demo/main.go create mode 100644 code-examples/go/materialize-demo/readme.MD diff --git a/code-examples/go/materialize-demo/authzed-download-fbc717.yaml b/code-examples/go/materialize-demo/authzed-download-fbc717.yaml new file mode 100644 index 0000000..967867f --- /dev/null +++ b/code-examples/go/materialize-demo/authzed-download-fbc717.yaml @@ -0,0 +1,29 @@ +schema: |- + + definition user {} + + definition organization { + relation member: user + } + + definition folder { + relation viewer: user + relation organization: organization + + permission view_doc = viewer & organization->member + } + + definition document { + relation folder: folder + permission view = folder->view_doc + } +relationships: |- + document:123#folder@folder:abc + folder:abc#organization@organization:acme + organization:acme#member@user:tim + folder:abc#viewer@user:tim + document:456#folder@folder:abc +assertions: + assertTrue: [] + assertFalse: [] +validation: {} diff --git a/code-examples/go/materialize-demo/cleanup.sh b/code-examples/go/materialize-demo/cleanup.sh new file mode 100755 index 0000000..8ee8cc8 --- /dev/null +++ b/code-examples/go/materialize-demo/cleanup.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +#to do: handle this in the app logic + +# Find the process ID (PID) using lsof to identify processes using port 5432 +PID=$(lsof -ti :5432) + +# Check if PID is not empty +if [ -z "$PID" ]; then + echo "No process is running on port 5432." +else + # Kill the process + kill -9 $PID + echo "Killed process with PID $PID running on port 5432." +fi + +zed relationship delete document:789 folder folder:abc --endpoint=materialize-demo-epic-herring-5707.us-east-1.demo.aws.authzed.net:443 --token=sdbst_h256_e4b91fcb2d3eb39d75c507b5fc4595494aa36f70db44f39a8a0ab5c3ba6eb836be7d8b225a0cd1bd8a036aed5e461dd0ab044dca0dbc525a2026638e2aa8dd3521bbeb74fdfc752f440e56010c48a42208fbd2b198f59e46030ef7e33db40c4e \ No newline at end of file diff --git a/code-examples/go/materialize-demo/go.mod b/code-examples/go/materialize-demo/go.mod new file mode 100644 index 0000000..cc9ad3f --- /dev/null +++ b/code-examples/go/materialize-demo/go.mod @@ -0,0 +1,45 @@ +module materialize + +go 1.22.5 + +require ( + github.com/authzed/authzed-go v0.14.0 + github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b + github.com/fatih/color v1.18.0 + github.com/fergusstrange/embedded-postgres v1.28.0 + github.com/jackc/pgx/v5 v5.6.0 + github.com/jzelinskie/stringz v0.0.3 + github.com/kataras/golog v0.1.12 + google.golang.org/grpc v1.65.0 + google.golang.org/protobuf v1.34.2 +) + +require ( + cloud.google.com/go/compute/metadata v0.3.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/kataras/pio v0.0.13 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/planetscale/vtprotobuf v0.6.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/samber/lo v1.46.0 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/code-examples/go/materialize-demo/go.sum b/code-examples/go/materialize-demo/go.sum new file mode 100644 index 0000000..5c217f0 --- /dev/null +++ b/code-examples/go/materialize-demo/go.sum @@ -0,0 +1,198 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/authzed/authzed-go v0.14.0 h1:Lvy0qudgdunuQmzsrO9ljNeCr7Cdfh2x1RwgOPi+M9w= +github.com/authzed/authzed-go v0.14.0/go.mod h1:ZyMR4heb6r5t3LJSu84AoxFXQUtaE+nYBbIvBx6vz5s= +github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b h1:wbh8IK+aMLTCey9sZasO7b6BWLAJnHHvb79fvWCXwxw= +github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b/go.mod h1:s3qC7V7XIbiNWERv7Lfljy/Lx25/V1Qlexb0WJuA8uQ= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= +github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fergusstrange/embedded-postgres v1.28.0 h1:Atixd24HCuBHBavnG4eiZAjRizOViwUahKGSjJdz1SU= +github.com/fergusstrange/embedded-postgres v1.28.0/go.mod h1:t/MLs0h9ukYM6FSt99R7InCHs1nW0ordoVCcnzmpTYw= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 h1:CWyXh/jylQWp2dtiV33mY4iSSp6yf4lmn+c7/tN+ObI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jzelinskie/stringz v0.0.3 h1:0GhG3lVMYrYtIvRbxvQI6zqRTT1P1xyQlpa0FhfUXas= +github.com/jzelinskie/stringz v0.0.3/go.mod h1:hHYbgxJuNLRw91CmpuFsYEOyQqpDVFg8pvEh23vy4P0= +github.com/kataras/golog v0.1.12 h1:Bu7I/G4ilJlbfzjmU39O9N+2uO1pBcMK045fzZ4ytNg= +github.com/kataras/golog v0.1.12/go.mod h1:wrGSbOiBqbQSQznleVNX4epWM8rl9SJ/rmEacl0yqy4= +github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM= +github.com/kataras/pio v0.0.13/go.mod h1:k3HNuSw+eJ8Pm2lA4lRhg3DiCjVgHlP8hmXApSej3oM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA= +github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ= +github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a h1:YIa/rzVqMEokBkPtydCkx1VLmv3An1Uw7w1P1m6EhOY= +google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:AHT0dDg3SoMOgZGnZk29b5xTbPHMoEC8qthmBLJCpys= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/code-examples/go/materialize-demo/internal/data/load.go b/code-examples/go/materialize-demo/internal/data/load.go new file mode 100644 index 0000000..1cde8d4 --- /dev/null +++ b/code-examples/go/materialize-demo/internal/data/load.go @@ -0,0 +1,71 @@ +package data + +import ( + "context" + "fmt" + "log" + + v0 "github.com/authzed/authzed-go/proto/authzed/api/materialize/v0" + "github.com/fatih/color" + "github.com/kataras/golog" + "google.golang.org/protobuf/encoding/prototext" +) + +func Write(change *v0.PermissionSetChange) { + + switch oneOf := change.GetChild().(type) { + //s2s + case *v0.PermissionSetChange_ChildSet: + s2s(change, oneOf) + color.Blue(prototext.Format(change)) + fmt.Println("------------------------------------------------") + //m2s + case *v0.PermissionSetChange_ChildMember: + m2s(change, oneOf) + color.Green(prototext.Format(change)) + fmt.Println("------------------------------------------------") + default: + log.Fatalf("Unknown child type") + } + +} + +func s2s(change *v0.PermissionSetChange, childSet *v0.PermissionSetChange_ChildSet) { + //see comment above + conn := connInit("sets") + defer conn.Close(context.Background()) + + query := `INSERT INTO set_to_set (child_type, child_id, child_relation, parent_type, parent_id, parent_relation) + VALUES ($1, $2, $3, $4, $5, $6)` + _, err := conn.Exec(context.Background(), query, + childSet.ChildSet.ObjectType, + childSet.ChildSet.ObjectId, + childSet.ChildSet.PermissionOrRelation, + change.ParentSet.ObjectType, + change.ParentSet.ObjectId, + change.ParentSet.PermissionOrRelation) + if err != nil { + golog.Errorf("unable to insert %v into set_to_set table: %v", change, err) + } + +} + +func m2s(change *v0.PermissionSetChange, childMember *v0.PermissionSetChange_ChildMember) { + //I wonder if this is the most effecient way to init the conn + conn := connInit("sets") + defer conn.Close(context.Background()) + + query := `INSERT INTO member_to_set (member_type, member_id, member_relation, set_type, set_id, set_relation) + VALUES ($1, $2, $3, $4, $5, $6)` + _, err := conn.Exec(context.Background(), query, + childMember.ChildMember.ObjectType, + childMember.ChildMember.ObjectId, + childMember.ChildMember.OptionalPermissionOrRelation, + change.ParentSet.ObjectType, + change.ParentSet.ObjectId, + change.ParentSet.PermissionOrRelation) + if err != nil { + golog.Errorf("unable to insert %v into member_to_set table: %v", change, err) + } + +} diff --git a/code-examples/go/materialize-demo/internal/data/postgres_init.go b/code-examples/go/materialize-demo/internal/data/postgres_init.go new file mode 100644 index 0000000..237ec6d --- /dev/null +++ b/code-examples/go/materialize-demo/internal/data/postgres_init.go @@ -0,0 +1,153 @@ +package data + +import ( + "fmt" + "log" + + "github.com/fatih/color" + embeddedpostgres "github.com/fergusstrange/embedded-postgres" + "github.com/kataras/golog" + + "context" + "io" + + "github.com/jackc/pgx/v5" + + "strings" +) + +func DbStart() (*embeddedpostgres.EmbeddedPostgres, error) { + golog.Info("Starting embedded postgres") + + // Redirect the embedded postgres logs to ioutil.Discard to suppress them + postgres := embeddedpostgres.NewDatabase(embeddedpostgres.DefaultConfig(). + Logger(io.Discard)) + err := postgres.Start() + if err != nil { + return postgres, err + } + + golog.Info("Started embedded postgres") + + return postgres, nil +} + +// to do: stop the db in the event of a fatalf +func DbStop(postgres *embeddedpostgres.EmbeddedPostgres) error { + golog.Info("Stopping embedded postgres") + err := postgres.Stop() + if err != nil { + return err + } + golog.Info("Stopped embedded postgres") + + return nil +} + +// connInit lets you specify the logical database you want to connect to +func connInit(db string) *pgx.Conn { + conn, err := pgx.Connect(context.Background(), "postgres://postgres:postgres@localhost:5432/"+db) + if err != nil { + log.Fatalf("unable to connect to database: %v", err) + } + + return conn +} + +func createDatabase() error { + + golog.Info("Creating logical database called 'sets'") + + conn := connInit("postgres") + defer conn.Close(context.Background()) + + // Create the database if it doesn't exist + _, err := conn.Exec(context.Background(), "CREATE DATABASE sets") + + if err != nil { + if strings.Contains(err.Error(), "SQLSTATE 42P04") { + golog.Info("Database called 'sets' already exists. Continuing...") + return nil + } + return err + } + + return nil +} + +func truncateTable(tableName string) error { + conn := connInit("sets") + defer conn.Close(context.Background()) + + _, err := conn.Exec(context.Background(), "TRUNCATE TABLE "+tableName+";") + if err != nil { + golog.Error(err) + return err + } + + return nil +} + +func createTables() error { + conn := connInit("sets") + defer conn.Close(context.Background()) + + m2sTable := `CREATE TABLE member_to_set ( + member_type varchar(100), + member_id varchar(100), + member_relation varchar(100), + set_type varchar(100), + set_id varchar(100), + set_relation varchar(100) + );` + _, err := conn.Exec(context.Background(), m2sTable) + + if err != nil { + if strings.Contains(err.Error(), "SQLSTATE 42P07") { + truncateTable("member_to_set") + golog.Info("Table member_to_set already exists. Table truncated and continuing...") + } else { + return err + } + } else { + color.Set(color.FgGreen) + fmt.Printf("Created member_to_set table: %v\n", m2sTable) + color.Unset() + } + + s2sTable := `CREATE TABLE set_to_set ( + child_type varchar(100), + child_id varchar(100), + child_relation varchar(100), + parent_type varchar(100), + parent_id varchar(100), + parent_relation varchar(100) + );` + _, err = conn.Exec(context.Background(), s2sTable) + if err != nil { + if strings.Contains(err.Error(), "SQLSTATE 42P07") { + truncateTable("set_to_set") + golog.Info("Table set_to_set already exists. Table truncated and continuing...") + return nil + } + return err + } else { + color.Set(color.FgBlue) + fmt.Printf("Created set_to_set table: %v\n", s2sTable) + color.Unset() + } + return nil +} + +func PrepareDatabase() error { + err := createDatabase() + if err != nil { + return err + } + err = createTables() + if err != nil { + return err + } + + return nil +} diff --git a/code-examples/go/materialize-demo/internal/data/read.go b/code-examples/go/materialize-demo/internal/data/read.go new file mode 100644 index 0000000..0b1a814 --- /dev/null +++ b/code-examples/go/materialize-demo/internal/data/read.go @@ -0,0 +1,143 @@ +package data + +import ( + "context" + "fmt" + "log" + "os" + + "text/tabwriter" + + "github.com/fatih/color" + "github.com/kataras/golog" +) + +// PrintTableContents prints the contents of the member_to_set and set_to_set tables +func PrintTableContents() error { + golog.Info("Printing table contents") + + err := printMemberToSet() + if err != nil { + return err + } + err = printSetToSet() + if err != nil { + return err + } + + return nil +} + +// printMemberToSet prints the contents of the member_to_set table +func printMemberToSet() error { + conn := connInit("sets") + defer conn.Close(context.Background()) + + rows, err := conn.Query(context.Background(), "SELECT member_type, member_id, member_relation, set_type, set_id, set_relation FROM member_to_set") + if err != nil { + return err + } + defer rows.Close() + + fmt.Println("\nContents of member_to_set:") + w := tabwriter.NewWriter(os.Stdout, 15, 0, 1, ' ', tabwriter.AlignRight|tabwriter.Debug) + fmt.Fprintln(w, "MemberType\tMemberID\tMemberRelation\tSetType\tSetID\tSetRelation\t") + + color.Set(color.FgGreen) + + for rows.Next() { + var memberType, memberId, memberRelation, setType, setId, setRelation string + err := rows.Scan(&memberType, &memberId, &memberRelation, &setType, &setId, &setRelation) + if err != nil { + log.Fatalf("unable to scan member_to_set row: %v", err) + } + fmt.Fprint(w, memberType+"\t") + fmt.Fprint(w, memberId+"\t") + fmt.Fprint(w, memberRelation+"\t") + fmt.Fprint(w, setType+"\t") + fmt.Fprint(w, setId+"\t") + fmt.Fprintln(w, setRelation+"\t") + } + w.Flush() + + color.Unset() + return nil +} + +// printSetToSet prints the contents of the set_to_set table +func printSetToSet() error { + conn := connInit("sets") + defer conn.Close(context.Background()) + + rows, err := conn.Query(context.Background(), "SELECT child_type, child_id, child_relation, parent_type, parent_id, parent_relation FROM set_to_set") + if err != nil { + return err + } + defer rows.Close() + + fmt.Println("\nContents of set_to_set:") + color.Set(color.FgBlue) + w := tabwriter.NewWriter(os.Stdout, 15, 0, 1, ' ', tabwriter.AlignRight|tabwriter.Debug) + fmt.Fprintln(w, "ChildType\tChildID\tChildRelation\tParentType\tParentID\tParentRelation\t") + + for rows.Next() { + var childType, childId, childRelation, parentType, parentId, parentRelation string + err := rows.Scan(&childType, &childId, &childRelation, &parentType, &parentId, &parentRelation) + if err != nil { + log.Fatalf("unable to scan set_to_set row: %v", err) + } + fmt.Fprint(w, childType+"\t") + fmt.Fprint(w, childId+"\t") + fmt.Fprint(w, childRelation+"\t") + fmt.Fprint(w, parentType+"\t") + fmt.Fprint(w, parentId+"\t") + fmt.Fprintln(w, parentRelation+"\t") + } + w.Flush() + color.Unset() + return nil +} + +func FindDocumentsUserCanView(userID string) error { + conn := connInit("sets") + defer conn.Close(context.Background()) + + query := ` + SELECT DISTINCT + s2s.parent_id AS document_id + FROM + member_to_set mts + JOIN + set_to_set s2s + ON + mts.set_type = s2s.child_type + AND mts.set_id = s2s.child_id + WHERE + mts.member_type = 'user' + AND mts.member_id = $1; + ` + color.Set(color.FgYellow) + fmt.Printf("Performing query to find documents user can view: %s\n", query) + color.Unset() + + rows, err := conn.Query(context.Background(), query, userID) + if err != nil { + return err + } + defer rows.Close() + + fmt.Printf("Documents that user %s can view:\n", userID) + color.Set(color.FgRed) + for rows.Next() { + var documentID string + err := rows.Scan(&documentID) + if err != nil { + return err + } + fmt.Printf("%s\n", + documentID) + } + color.Unset() + + return nil +} diff --git a/code-examples/go/materialize-demo/internal/spice/spice.go b/code-examples/go/materialize-demo/internal/spice/spice.go new file mode 100644 index 0000000..c54c04b --- /dev/null +++ b/code-examples/go/materialize-demo/internal/spice/spice.go @@ -0,0 +1,121 @@ +package spice + +import ( + "context" + "log" + + pb "github.com/authzed/authzed-go/proto/authzed/api/v1" + "github.com/authzed/authzed-go/v1" + "github.com/authzed/grpcutil" + "github.com/fatih/color" + "github.com/jzelinskie/stringz" + "github.com/kataras/golog" +) + +func clientInit() *authzed.Client { + systemCerts, err := grpcutil.WithSystemCerts(grpcutil.VerifyCA) + if err != nil { + log.Fatalf("unable to load system CA certificates: %s", err) + } + + spiceClient, err := authzed.NewClient( + "materialize-demo-epic-herring-5707.us-east-1.demo.aws.authzed.net:443", + grpcutil.WithBearerToken("sdbst_h256_e4b91fcb2d3eb39d75c507b5fc4595494aa36f70db44f39a8a0ab5c3ba6eb836be7d8b225a0cd1bd8a036aed5e461dd0ab044dca0dbc525a2026638e2aa8dd3521bbeb74fdfc752f440e56010c48a42208fbd2b198f59e46030ef7e33db40c4e"), + systemCerts, + ) + if err != nil { + log.Fatalf("unable to initialize client: %s", err) + } + + return spiceClient +} + +func ReadSchema() error { + client := clientInit() + + request := &pb.ReadSchemaRequest{} + + resp, err := client.ReadSchema(context.Background(), request) + + //todo: look at how zed formats the schema, maybe use a library from there for this + if err != nil { + return err + } else { + color.Blue(stringz.Join("\n\n", resp.SchemaText)) + } + return nil +} + +func WriteRelationship() error { + client := clientInit() + + objectType := "document" + objectID := "789" + relation := "folder" + subjectObjectType := "folder" + subjectObjectID := "abc" + + request := &pb.WriteRelationshipsRequest{Updates: []*pb.RelationshipUpdate{ + { + Operation: pb.RelationshipUpdate_OPERATION_CREATE, + Relationship: &pb.Relationship{ + Resource: &pb.ObjectReference{ + ObjectType: objectType, + ObjectId: objectID, + }, + Relation: relation, + Subject: &pb.SubjectReference{ + Object: &pb.ObjectReference{ + ObjectType: subjectObjectType, + ObjectId: subjectObjectID, + }, + }, + }, + }, + }} + _, err := client.WriteRelationships(context.Background(), request) + if err != nil { + return err + } + + golog.Infof("Wrote relationship: %s %s %s %s %s", objectType, objectID, relation, subjectObjectType, subjectObjectID) + + return nil +} + +func DeleteRelationship() error { + client := clientInit() + + objectType := "document" + objectID := "789" + relation := "folder" + subjectObjectType := "folder" + subjectObjectID := "abc" + + request := &pb.WriteRelationshipsRequest{Updates: []*pb.RelationshipUpdate{ + { + Operation: pb.RelationshipUpdate_OPERATION_DELETE, + Relationship: &pb.Relationship{ + Resource: &pb.ObjectReference{ + ObjectType: objectType, + ObjectId: objectID, + }, + Relation: relation, + Subject: &pb.SubjectReference{ + Object: &pb.ObjectReference{ + ObjectType: subjectObjectType, + ObjectId: subjectObjectID, + }, + }, + }, + }, + }} + _, err := client.WriteRelationships(context.Background(), request) + if err != nil { + return err + } + + golog.Infof("Cleaned up (deleted) relationship: %s %s %s %s %s", objectType, objectID, relation, subjectObjectType, subjectObjectID) + + return nil +} diff --git a/code-examples/go/materialize-demo/internal/tiger/tiger.go b/code-examples/go/materialize-demo/internal/tiger/tiger.go new file mode 100644 index 0000000..6d63ee1 --- /dev/null +++ b/code-examples/go/materialize-demo/internal/tiger/tiger.go @@ -0,0 +1,106 @@ +package tiger + +import ( + "context" + "errors" + "fmt" + "io" + "log" + "materialize/internal/data" + + v0 "github.com/authzed/authzed-go/proto/authzed/api/materialize/v0" + "github.com/authzed/grpcutil" + "github.com/kataras/golog" + "google.golang.org/grpc" +) + +func clientInit() *grpc.ClientConn { + systemCerts, err := grpcutil.WithSystemCerts(grpcutil.SkipVerifyCA) + if err != nil { + log.Fatalf("unable to load system CA certificates: %s", err) + } + + // Correct the gRPC connection initialization + tigerConn, err := grpc.NewClient( + "localhost:50054", + systemCerts, + grpcutil.WithBearerToken("sdbpk_8466b13439e4db1f8cabaf377ce8db8cc8643ae4ddd20cec990340170dfdc714d5461e51723766851aba0e845ce815ca104d9ff04384c96195ae156d2952e49a579d8caf2b06e71918926df4cbe09c2cc1b279cdc734ca31573dbca542a3ce7c"), + ) + if err != nil { + log.Fatalf("failed to connect to gRPC server: %v", err) + } + + return tigerConn +} + +func Lps() error { + tigerConn := clientInit() + + defer tigerConn.Close() + + tigerClient := v0.NewWatchPermissionSetsServiceClient(tigerConn) + + //to do: implement a loop here + stream, err := tigerClient.LookupPermissionSets(context.Background(), &v0.LookupPermissionSetsRequest{ + Limit: uint32(500), + }) + if err != nil { + return err + } + + resp, err := stream.Recv() + if err != nil { + return err + } + + golog.Info("Streaming initial hydration of permission sets from LookupPermissionSets API") + + data.Write(resp.Change) + + for { + resp, err = stream.Recv() + if errors.Is(err, io.EOF) { + break + } + + data.Write(resp.Change) + } + + return nil +} + +func Wps() error { + + tigerConn := clientInit() + + defer tigerConn.Close() + + tigerClient := v0.NewWatchPermissionSetsServiceClient(tigerConn) + + golog.Info("Streaming updates from WatchPermissionSets API...") + + stream, err := tigerClient.WatchPermissionSets(context.Background(), &v0.WatchPermissionSetsRequest{ /*zed token could go here*/ }) + if err != nil { + return err + } + + for { + resp, err := stream.Recv() + if errors.Is(err, io.EOF) { + break + } + switch response := resp.Response.(type) { + case *v0.WatchPermissionSetsResponse_Change: + data.Write(response.Change) + case *v0.WatchPermissionSetsResponse_CompletedRevision: + //todo: fix this jankiness + fmt.Println("") + case *v0.WatchPermissionSetsResponse_LookupPermissionSetsRequired: + fmt.Println("") + default: + fmt.Println("Unknown response type") + } + + } + return nil +} diff --git a/code-examples/go/materialize-demo/main.go b/code-examples/go/materialize-demo/main.go new file mode 100644 index 0000000..d9ed44d --- /dev/null +++ b/code-examples/go/materialize-demo/main.go @@ -0,0 +1,134 @@ +package main + +import ( + "bufio" + "fmt" + "materialize/internal/data" + "materialize/internal/spice" + "materialize/internal/tiger" + "os" + "strings" + "sync" + "time" + + "github.com/kataras/golog" +) + +func init() { +} + +func main() { + defer fmt.Println("Goodbye!") + + fmt.Println("Welcome to the WatchPermissionSets demonstration!") + fmt.Println("\nHere is the schema for todays demo:\n") + err := spice.ReadSchema() + if err != nil { + golog.Errorf("unable to read schema: %v", err) + return + } + fmt.Println("") + fmt.Println("Also, the Permission System has been seeded with some initial relationship data.") + halt() + //spins up embedded in-memory postgres DB + //"db" is needed to stop at the end of the program + db, err := data.DbStart() + if err != nil { + golog.Errorf("unable to start embedded postgres: %v", err) + golog.Info("assuming postgres already running (embedded or standalone), continuing...") + } + //cleans up embedded in-memory postgres DB + defer func() { + err := data.DbStop(db) + if err != nil { + golog.Errorf("unable to stop embedded postgres: %v", err) + return + } + }() + + err = data.PrepareDatabase() + if err != nil { + golog.Errorf("unable to prepare database: %v", err) + return + } + maxRetries := 2 + for i := 0; i <= maxRetries; i++ { + halt() + err = tiger.Lps() + if err != nil { + golog.Errorf("unable to hydrate permission sets: %v", err) + } + if err == nil { + break + } + if i == maxRetries { + golog.Errorf("unable to hydrate permission sets after %d retries: %v", maxRetries, err) + return + } + } + + halt() + err = data.PrintTableContents() + if err != nil { + golog.Errorf("unable to print table contents: %v", err) + return + } + halt() + err = data.FindDocumentsUserCanView("tim") + if err != nil { + golog.Errorf("unable to find documents user can view: %v", err) + return + } + halt() + + var wg sync.WaitGroup + + wg.Add(1) + + go func() { + defer wg.Done() + tiger.Wps() + }() + + time.Sleep(2 * time.Second) + + err = spice.WriteRelationship() + if err != nil { + if strings.Contains(err.Error(), "AlreadyExists") { + err = spice.DeleteRelationship() + if err != nil { + golog.Errorf("unable to delete relationship: %v", err) + return + } + err = spice.WriteRelationship() + if err != nil { + golog.Errorf("unable to write relationship, after deleting it: %v", err) + return + } + } else { + golog.Errorf("unable to write relationship: %v", err) + return + } + } + + defer func() { + err = spice.DeleteRelationship() + if err != nil { + golog.Errorf("unable to delete relationship: %v", err) + return + } + }() + + halt() + err = data.FindDocumentsUserCanView("tim") + if err != nil { + golog.Errorf("unable to find documents user can view: %v", err) + return + } + +} + +func halt() { + fmt.Print("Press 'Enter' to continue...\n") + bufio.NewReader(os.Stdin).ReadBytes('\n') +} diff --git a/code-examples/go/materialize-demo/readme.MD b/code-examples/go/materialize-demo/readme.MD new file mode 100644 index 0000000..a1f577d --- /dev/null +++ b/code-examples/go/materialize-demo/readme.MD @@ -0,0 +1,11 @@ +# Authzed Materialize Demo + +## Notes for Readers Outside of Authzed + +This is the code used for the Authzed Materialize demo. This code provides some examples of how to integrate with Materialize using the Authzed Go client. It's not intended for you to run this code. + +Materialize is only available on Authzed Dedicated. Reach out to support@authzed.com if you's like to try it out. + +## Internal Authzed Notes + +See [internal Authzed notion](https://www.notion.so/authzed/Materialize-Demo-19e74d961cd780acabb7f7b2c10dd6b9?pvs=4). \ No newline at end of file From 15536ebbca8589f019785657850aab970a3e066e Mon Sep 17 00:00:00 2001 From: Evan Corkrean <62527488+corkrean@users.noreply.github.com> Date: Tue, 18 Feb 2025 14:22:55 -0700 Subject: [PATCH 2/6] materialize demo disclaimer --- code-examples/go/materialize-demo/readme.MD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code-examples/go/materialize-demo/readme.MD b/code-examples/go/materialize-demo/readme.MD index a1f577d..9f258ec 100644 --- a/code-examples/go/materialize-demo/readme.MD +++ b/code-examples/go/materialize-demo/readme.MD @@ -4,6 +4,8 @@ This is the code used for the Authzed Materialize demo. This code provides some examples of how to integrate with Materialize using the Authzed Go client. It's not intended for you to run this code. +Please be aware that this program is for demonstration and educational purposes. You might take different approaches when integrating with Materialize in a prod env. + Materialize is only available on Authzed Dedicated. Reach out to support@authzed.com if you's like to try it out. ## Internal Authzed Notes From c1d9146a4902eafac3b3dac81168279d29a4c47a Mon Sep 17 00:00:00 2001 From: Evan Corkrean <62527488+corkrean@users.noreply.github.com> Date: Tue, 18 Feb 2025 14:28:32 -0700 Subject: [PATCH 3/6] materialize demo: making linter happy --- .../authzed-download-fbc717.yaml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/code-examples/go/materialize-demo/authzed-download-fbc717.yaml b/code-examples/go/materialize-demo/authzed-download-fbc717.yaml index 967867f..8b21b4e 100644 --- a/code-examples/go/materialize-demo/authzed-download-fbc717.yaml +++ b/code-examples/go/materialize-demo/authzed-download-fbc717.yaml @@ -1,29 +1,32 @@ +--- schema: |- - definition user {} definition organization { - relation member: user + relation member: user } definition folder { - relation viewer: user - relation organization: organization + relation viewer: user + relation organization: organization - permission view_doc = viewer & organization->member + permission view_doc = viewer & organization->member } definition document { - relation folder: folder - permission view = folder->view_doc + relation folder: folder + permission view = folder->view_doc } + relationships: |- document:123#folder@folder:abc folder:abc#organization@organization:acme organization:acme#member@user:tim folder:abc#viewer@user:tim document:456#folder@folder:abc + assertions: assertTrue: [] assertFalse: [] -validation: {} + +validation: {} \ No newline at end of file From e45a62076da347e0197e3edc80688016afbb0646 Mon Sep 17 00:00:00 2001 From: Evan Corkrean <62527488+corkrean@users.noreply.github.com> Date: Tue, 18 Feb 2025 14:30:16 -0700 Subject: [PATCH 4/6] materialize demo: making linter happy pt 2 --- code-examples/go/materialize-demo/authzed-download-fbc717.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code-examples/go/materialize-demo/authzed-download-fbc717.yaml b/code-examples/go/materialize-demo/authzed-download-fbc717.yaml index 8b21b4e..dbfcb48 100644 --- a/code-examples/go/materialize-demo/authzed-download-fbc717.yaml +++ b/code-examples/go/materialize-demo/authzed-download-fbc717.yaml @@ -29,4 +29,4 @@ assertions: assertTrue: [] assertFalse: [] -validation: {} \ No newline at end of file +validation: {} From 4345e2f0074b2c422fc66a7c0c82dcce435d3b2a Mon Sep 17 00:00:00 2001 From: Evan Corkrean <62527488+corkrean@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:24:12 -0700 Subject: [PATCH 5/6] change --- code-examples/go/materialize-demo/internal/spice/spice.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code-examples/go/materialize-demo/internal/spice/spice.go b/code-examples/go/materialize-demo/internal/spice/spice.go index c54c04b..9d38904 100644 --- a/code-examples/go/materialize-demo/internal/spice/spice.go +++ b/code-examples/go/materialize-demo/internal/spice/spice.go @@ -20,7 +20,8 @@ func clientInit() *authzed.Client { spiceClient, err := authzed.NewClient( "materialize-demo-epic-herring-5707.us-east-1.demo.aws.authzed.net:443", - grpcutil.WithBearerToken("sdbst_h256_e4b91fcb2d3eb39d75c507b5fc4595494aa36f70db44f39a8a0ab5c3ba6eb836be7d8b225a0cd1bd8a036aed5e461dd0ab044dca0dbc525a2026638e2aa8dd3521bbeb74fdfc752f440e56010c48a42208fbd2b198f59e46030ef7e33db40c4e"), + //insert token here + grpcutil.WithBearerToken(""), systemCerts, ) if err != nil { From 062a2d2122f1e3089c4aa48fe5378bf788bc7fdc Mon Sep 17 00:00:00 2001 From: Evan Corkrean <62527488+corkrean@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:37:28 -0700 Subject: [PATCH 6/6] change 2 --- code-examples/go/materialize-demo/internal/tiger/tiger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code-examples/go/materialize-demo/internal/tiger/tiger.go b/code-examples/go/materialize-demo/internal/tiger/tiger.go index 6d63ee1..a1e4d93 100644 --- a/code-examples/go/materialize-demo/internal/tiger/tiger.go +++ b/code-examples/go/materialize-demo/internal/tiger/tiger.go @@ -24,7 +24,7 @@ func clientInit() *grpc.ClientConn { tigerConn, err := grpc.NewClient( "localhost:50054", systemCerts, - grpcutil.WithBearerToken("sdbpk_8466b13439e4db1f8cabaf377ce8db8cc8643ae4ddd20cec990340170dfdc714d5461e51723766851aba0e845ce815ca104d9ff04384c96195ae156d2952e49a579d8caf2b06e71918926df4cbe09c2cc1b279cdc734ca31573dbca542a3ce7c"), + grpcutil.WithBearerToken(""), ) if err != nil { log.Fatalf("failed to connect to gRPC server: %v", err)