code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/oracle_spec.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package sqlstore 17 18 import ( 19 "context" 20 "fmt" 21 22 "code.vegaprotocol.io/vega/datanode/entities" 23 "code.vegaprotocol.io/vega/datanode/metrics" 24 v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2" 25 26 "github.com/georgysavva/scany/pgxscan" 27 ) 28 29 type OracleSpec struct { 30 *ConnectionSource 31 } 32 33 var oracleSpecOrdering = TableOrdering{ 34 ColumnOrdering{Name: "id", Sorting: ASC}, 35 ColumnOrdering{Name: "vega_time", Sorting: ASC}, 36 } 37 38 const ( 39 sqlOracleSpecColumns = `id, created_at, updated_at, data, status, tx_hash, vega_time` 40 ) 41 42 func NewOracleSpec(connectionSource *ConnectionSource) *OracleSpec { 43 return &OracleSpec{ 44 ConnectionSource: connectionSource, 45 } 46 } 47 48 func (os *OracleSpec) Upsert(ctx context.Context, spec *entities.OracleSpec) error { 49 query := fmt.Sprintf(`insert into oracle_specs(%s) 50 values ($1, $2, $3, $4, $5, $6, $7) 51 on conflict (id, vega_time) do update 52 set 53 created_at=EXCLUDED.created_at, 54 updated_at=EXCLUDED.updated_at, 55 data=EXCLUDED.data, 56 status=EXCLUDED.status, 57 tx_hash=EXCLUDED.tx_hash`, sqlOracleSpecColumns) 58 59 defer metrics.StartSQLQuery("OracleSpec", "Upsert")() 60 specData := spec.ExternalDataSourceSpec.Spec 61 if _, err := os.Exec(ctx, query, specData.ID, specData.CreatedAt, specData.UpdatedAt, specData.Data, 62 specData.Status, specData.TxHash, specData.VegaTime); err != nil { 63 return err 64 } 65 66 return nil 67 } 68 69 func (os *OracleSpec) GetSpecByID(ctx context.Context, specID string) (*entities.OracleSpec, error) { 70 defer metrics.StartSQLQuery("OracleSpec", "GetByID")() 71 72 var spec entities.DataSourceSpec 73 query := fmt.Sprintf(`%s 74 where id = $1 75 order by id, vega_time desc`, getOracleSpecsQuery()) 76 77 err := pgxscan.Get(ctx, os.ConnectionSource, &spec, query, entities.SpecID(specID)) 78 if err != nil { 79 return nil, os.wrapE(err) 80 } 81 return &entities.OracleSpec{ 82 ExternalDataSourceSpec: &entities.ExternalDataSourceSpec{ 83 Spec: &spec, 84 }, 85 }, err 86 } 87 88 func (os *OracleSpec) GetByTxHash(ctx context.Context, txHash entities.TxHash) ([]entities.OracleSpec, error) { 89 defer metrics.StartSQLQuery("OracleSpec", "GetByTxHash")() 90 91 var specs []*entities.DataSourceSpec 92 query := "SELECT * FROM oracle_specs WHERE tx_hash = $1" 93 err := pgxscan.Select(ctx, os.ConnectionSource, &specs, query, txHash) 94 if err != nil { 95 return nil, os.wrapE(err) 96 } 97 98 oSpecs := []entities.OracleSpec{} 99 for _, spec := range specs { 100 oSpecs = append(oSpecs, entities.OracleSpec{ExternalDataSourceSpec: &entities.ExternalDataSourceSpec{Spec: spec}}) 101 } 102 103 return oSpecs, err 104 } 105 106 func (os *OracleSpec) GetSpecsWithCursorPagination(ctx context.Context, specID string, pagination entities.CursorPagination) ( 107 []entities.OracleSpec, entities.PageInfo, error, 108 ) { 109 if specID != "" { 110 return os.getSingleSpecWithPageInfo(ctx, specID) 111 } 112 113 return os.getSpecsWithPageInfo(ctx, pagination) 114 } 115 116 func (os *OracleSpec) getSingleSpecWithPageInfo(ctx context.Context, specID string) ([]entities.OracleSpec, entities.PageInfo, error) { 117 spec, err := os.GetSpecByID(ctx, specID) 118 if err != nil { 119 return nil, entities.PageInfo{}, err 120 } 121 122 return []entities.OracleSpec{*spec}, 123 entities.PageInfo{ 124 HasNextPage: false, 125 HasPreviousPage: false, 126 StartCursor: spec.Cursor().Encode(), 127 EndCursor: spec.Cursor().Encode(), 128 }, nil 129 } 130 131 func (os *OracleSpec) getSpecsWithPageInfo(ctx context.Context, pagination entities.CursorPagination) ( 132 []entities.OracleSpec, entities.PageInfo, error, 133 ) { 134 var ( 135 specs []entities.DataSourceSpec 136 oSpecs = []entities.OracleSpec{} 137 pageInfo entities.PageInfo 138 err error 139 args []interface{} 140 ) 141 142 query := getOracleSpecsQuery() 143 query, args, err = PaginateQuery[entities.DataSourceSpecCursor](query, args, oracleSpecOrdering, pagination) 144 if err != nil { 145 return nil, pageInfo, err 146 } 147 148 if err = pgxscan.Select(ctx, os.ConnectionSource, &specs, query, args...); err != nil { 149 return nil, pageInfo, fmt.Errorf("querying oracle specs: %w", err) 150 } 151 152 if len(specs) > 0 { 153 for i := range specs { 154 oSpecs = append(oSpecs, entities.OracleSpec{ 155 ExternalDataSourceSpec: &entities.ExternalDataSourceSpec{ 156 Spec: &specs[i], 157 }, 158 }) 159 } 160 } 161 oSpecs, pageInfo = entities.PageEntities[*v2.OracleSpecEdge](oSpecs, pagination) 162 163 return oSpecs, pageInfo, nil 164 } 165 166 func getOracleSpecsQuery() string { 167 return fmt.Sprintf(`select distinct on (id) %s 168 from oracle_specs`, sqlOracleSpecColumns) 169 }