feat(datatables): DataTables capability for site data table access
Wasm plugins' isolated Postgres role is deliberately denied on core tables, which left no sanctioned path to data_tables/data_table_rows. Adds the datatables.* capability family (get_table_by_key, get_row, list_rows, create_row, update_row_data, find_row_by_field) following the datasources pattern: interface package, ABI proto messages, guest stub, CoreServices wiring, golden round-trip coverage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
623ea2e14b
commit
6fd4c2f65d
@ -311,6 +311,79 @@ message DatasourceResult {
|
|||||||
bytes meta_json = 3;
|
bytes meta_json = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- datatables.* (datatables.DataTables) ---
|
||||||
|
|
||||||
|
message DatatablesGetTableByKeyRequest {
|
||||||
|
string table_key = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesGetTableByKeyResponse {
|
||||||
|
DataTableInfo table = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesGetRowRequest {
|
||||||
|
string row_id = 1; // UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesGetRowResponse {
|
||||||
|
DataTableRowInfo row = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesListRowsRequest {
|
||||||
|
string table_id = 1; // UUID
|
||||||
|
int32 limit = 2;
|
||||||
|
int32 offset = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesListRowsResponse {
|
||||||
|
repeated DataTableRowInfo rows = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesCreateRowRequest {
|
||||||
|
string table_id = 1; // UUID
|
||||||
|
bytes data_json = 2; // JSON object
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesCreateRowResponse {
|
||||||
|
DataTableRowInfo row = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesUpdateRowDataRequest {
|
||||||
|
string row_id = 1; // UUID
|
||||||
|
bytes data_json = 2; // JSON object
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesUpdateRowDataResponse {
|
||||||
|
DataTableRowInfo row = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesFindRowByFieldRequest {
|
||||||
|
string table_id = 1; // UUID
|
||||||
|
string field = 2;
|
||||||
|
string value = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DatatablesFindRowByFieldResponse {
|
||||||
|
// Unset when no row matches (the guest maps that to nil, nil).
|
||||||
|
DataTableRowInfo row = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataTableInfo mirrors datatables.Table.
|
||||||
|
message DataTableInfo {
|
||||||
|
string id = 1; // UUID
|
||||||
|
string table_key = 2;
|
||||||
|
string name = 3;
|
||||||
|
int32 row_count = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataTableRowInfo mirrors datatables.Row (data column as JSON bytes).
|
||||||
|
message DataTableRowInfo {
|
||||||
|
string id = 1; // UUID
|
||||||
|
string table_id = 2; // UUID
|
||||||
|
bytes data_json = 3; // JSON object
|
||||||
|
int32 sort_order = 4;
|
||||||
|
}
|
||||||
|
|
||||||
// --- users.* (auth.PublicUsers) ---
|
// --- users.* (auth.PublicUsers) ---
|
||||||
|
|
||||||
message UsersGetByUsernameRequest {
|
message UsersGetByUsernameRequest {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
46
datatables/datatables.go
Normal file
46
datatables/datatables.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Package datatables gives plugins typed access to site data tables (the Data
|
||||||
|
// Platform's data_tables/data_table_rows), which the per-plugin Postgres role
|
||||||
|
// deliberately cannot reach with raw SQL. The CMS implements this interface
|
||||||
|
// host-side and wires it into CoreServices; row payloads cross the ABI as JSON.
|
||||||
|
package datatables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DataTables provides read/write access to site data tables for plugins.
|
||||||
|
type DataTables interface {
|
||||||
|
// GetTableByKey resolves a data table by its stable key (e.g. "playgrounds").
|
||||||
|
GetTableByKey(ctx context.Context, tableKey string) (*Table, error)
|
||||||
|
// GetRow fetches a single row by ID.
|
||||||
|
GetRow(ctx context.Context, rowID uuid.UUID) (*Row, error)
|
||||||
|
// ListRows pages through a table's rows in sort order. limit <= 0 applies
|
||||||
|
// the host default.
|
||||||
|
ListRows(ctx context.Context, tableID uuid.UUID, limit, offset int32) ([]Row, error)
|
||||||
|
// CreateRow appends a row with the given JSON object payload.
|
||||||
|
CreateRow(ctx context.Context, tableID uuid.UUID, dataJSON []byte) (*Row, error)
|
||||||
|
// UpdateRowData replaces a row's JSON payload, preserving its sort order.
|
||||||
|
UpdateRowData(ctx context.Context, rowID uuid.UUID, dataJSON []byte) (*Row, error)
|
||||||
|
// FindRowByField returns the first row whose data->>field equals value, or
|
||||||
|
// (nil, nil) when no row matches.
|
||||||
|
FindRowByField(ctx context.Context, tableID uuid.UUID, field, value string) (*Row, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Table is a plugin-facing view of a data table.
|
||||||
|
type Table struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
TableKey string
|
||||||
|
Name string
|
||||||
|
RowCount int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Row is a plugin-facing view of a data table row. DataJSON is the row's data
|
||||||
|
// column verbatim (a JSON object).
|
||||||
|
type Row struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
TableID uuid.UUID
|
||||||
|
DataJSON []byte
|
||||||
|
SortOrder int32
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"git.dev.alexdunmow.com/block/pluginsdk/content"
|
"git.dev.alexdunmow.com/block/pluginsdk/content"
|
||||||
"git.dev.alexdunmow.com/block/pluginsdk/crypto"
|
"git.dev.alexdunmow.com/block/pluginsdk/crypto"
|
||||||
"git.dev.alexdunmow.com/block/pluginsdk/datasources"
|
"git.dev.alexdunmow.com/block/pluginsdk/datasources"
|
||||||
|
"git.dev.alexdunmow.com/block/pluginsdk/datatables"
|
||||||
"git.dev.alexdunmow.com/block/pluginsdk/gating"
|
"git.dev.alexdunmow.com/block/pluginsdk/gating"
|
||||||
"git.dev.alexdunmow.com/block/pluginsdk/menus"
|
"git.dev.alexdunmow.com/block/pluginsdk/menus"
|
||||||
"git.dev.alexdunmow.com/block/pluginsdk/settings"
|
"git.dev.alexdunmow.com/block/pluginsdk/settings"
|
||||||
@ -27,6 +28,7 @@ type CoreServices struct {
|
|||||||
Crypto crypto.Crypto
|
Crypto crypto.Crypto
|
||||||
Menus menus.Menus
|
Menus menus.Menus
|
||||||
Datasources datasources.Datasources
|
Datasources datasources.Datasources
|
||||||
|
DataTables datatables.DataTables
|
||||||
PublicUsers auth.PublicUsers
|
PublicUsers auth.PublicUsers
|
||||||
Subscriptions subscriptions.Subscriptions
|
Subscriptions subscriptions.Subscriptions
|
||||||
|
|
||||||
|
|||||||
@ -405,6 +405,90 @@ func TestCapabilityRoundTrip(t *testing.T) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// --- datatables ---
|
||||||
|
{
|
||||||
|
name: "datatables_get_table_by_key", wantMethod: "datatables.get_table_by_key",
|
||||||
|
resp: &abiv1.DatatablesGetTableByKeyResponse{Table: &abiv1.DataTableInfo{
|
||||||
|
Id: idTable.String(), TableKey: "playgrounds", Name: "Playgrounds", RowCount: 678,
|
||||||
|
}},
|
||||||
|
run: func(t *testing.T, cs plugin.CoreServices) {
|
||||||
|
got, err := cs.DataTables.GetTableByKey(ctx, "playgrounds")
|
||||||
|
if err != nil || got.ID != idTable || got.TableKey != "playgrounds" || got.RowCount != 678 {
|
||||||
|
t.Errorf("table = %+v err = %v", got, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "datatables_get_row", wantMethod: "datatables.get_row",
|
||||||
|
resp: &abiv1.DatatablesGetRowResponse{Row: &abiv1.DataTableRowInfo{
|
||||||
|
Id: idRow.String(), TableId: idTable.String(), DataJson: []byte(`{"name":"Whiteman Park"}`), SortOrder: 3,
|
||||||
|
}},
|
||||||
|
run: func(t *testing.T, cs plugin.CoreServices) {
|
||||||
|
got, err := cs.DataTables.GetRow(ctx, idRow)
|
||||||
|
if err != nil || got.ID != idRow || got.TableID != idTable || got.SortOrder != 3 {
|
||||||
|
t.Errorf("row = %+v err = %v", got, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "datatables_list_rows", wantMethod: "datatables.list_rows",
|
||||||
|
resp: &abiv1.DatatablesListRowsResponse{Rows: []*abiv1.DataTableRowInfo{
|
||||||
|
{Id: idRow.String(), TableId: idTable.String(), DataJson: []byte(`{"name":"A"}`)},
|
||||||
|
{Id: idItem.String(), TableId: idTable.String(), DataJson: []byte(`{"name":"B"}`), SortOrder: 1},
|
||||||
|
}},
|
||||||
|
run: func(t *testing.T, cs plugin.CoreServices) {
|
||||||
|
got, err := cs.DataTables.ListRows(ctx, idTable, 100, 0)
|
||||||
|
if err != nil || len(got) != 2 || got[0].ID != idRow || got[1].SortOrder != 1 {
|
||||||
|
t.Errorf("rows = %+v err = %v", got, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "datatables_create_row", wantMethod: "datatables.create_row",
|
||||||
|
resp: &abiv1.DatatablesCreateRowResponse{Row: &abiv1.DataTableRowInfo{
|
||||||
|
Id: idRow.String(), TableId: idTable.String(), DataJson: []byte(`{"name":"New"}`),
|
||||||
|
}},
|
||||||
|
run: func(t *testing.T, cs plugin.CoreServices) {
|
||||||
|
got, err := cs.DataTables.CreateRow(ctx, idTable, []byte(`{"name":"New"}`))
|
||||||
|
if err != nil || got.ID != idRow || string(got.DataJSON) != `{"name":"New"}` {
|
||||||
|
t.Errorf("row = %+v err = %v", got, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "datatables_update_row_data", wantMethod: "datatables.update_row_data",
|
||||||
|
resp: &abiv1.DatatablesUpdateRowDataResponse{Row: &abiv1.DataTableRowInfo{
|
||||||
|
Id: idRow.String(), TableId: idTable.String(), DataJson: []byte(`{"name":"Updated"}`), SortOrder: 7,
|
||||||
|
}},
|
||||||
|
run: func(t *testing.T, cs plugin.CoreServices) {
|
||||||
|
got, err := cs.DataTables.UpdateRowData(ctx, idRow, []byte(`{"name":"Updated"}`))
|
||||||
|
if err != nil || got.SortOrder != 7 || string(got.DataJSON) != `{"name":"Updated"}` {
|
||||||
|
t.Errorf("row = %+v err = %v", got, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "datatables_find_row_by_field", wantMethod: "datatables.find_row_by_field",
|
||||||
|
resp: &abiv1.DatatablesFindRowByFieldResponse{Row: &abiv1.DataTableRowInfo{
|
||||||
|
Id: idRow.String(), TableId: idTable.String(), DataJson: []byte(`{"google_place_id":"abc"}`),
|
||||||
|
}},
|
||||||
|
run: func(t *testing.T, cs plugin.CoreServices) {
|
||||||
|
got, err := cs.DataTables.FindRowByField(ctx, idTable, "google_place_id", "abc")
|
||||||
|
if err != nil || got == nil || got.ID != idRow {
|
||||||
|
t.Errorf("row = %+v err = %v", got, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "datatables_find_row_by_field_miss", wantMethod: "datatables.find_row_by_field",
|
||||||
|
resp: &abiv1.DatatablesFindRowByFieldResponse{},
|
||||||
|
run: func(t *testing.T, cs plugin.CoreServices) {
|
||||||
|
got, err := cs.DataTables.FindRowByField(ctx, idTable, "google_place_id", "missing")
|
||||||
|
if err != nil || got != nil {
|
||||||
|
t.Errorf("want nil, nil on miss; row = %+v err = %v", got, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
// --- users ---
|
// --- users ---
|
||||||
{
|
{
|
||||||
name: "users_get_by_username", wantMethod: "users.get_by_username",
|
name: "users_get_by_username", wantMethod: "users.get_by_username",
|
||||||
|
|||||||
@ -34,6 +34,7 @@ func NewCoreServices(call CallFunc) plugin.CoreServices {
|
|||||||
Crypto: &cryptoStub{base{family: "crypto", call: call}},
|
Crypto: &cryptoStub{base{family: "crypto", call: call}},
|
||||||
Menus: &menusStub{base{family: "menus", call: call}},
|
Menus: &menusStub{base{family: "menus", call: call}},
|
||||||
Datasources: &datasourcesStub{base{family: "datasources", call: call}},
|
Datasources: &datasourcesStub{base{family: "datasources", call: call}},
|
||||||
|
DataTables: &datatablesStub{base{family: "datatables", call: call}},
|
||||||
PublicUsers: &usersStub{base{family: "users", call: call}},
|
PublicUsers: &usersStub{base{family: "users", call: call}},
|
||||||
Subscriptions: &subscriptionsStub{base{family: "subscriptions", call: call}},
|
Subscriptions: &subscriptionsStub{base{family: "subscriptions", call: call}},
|
||||||
Media: &mediaStub{base{family: "media", call: call}},
|
Media: &mediaStub{base{family: "media", call: call}},
|
||||||
|
|||||||
102
plugin/wasmguest/caps/datatables.go
Normal file
102
plugin/wasmguest/caps/datatables.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package caps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
abiv1 "git.dev.alexdunmow.com/block/pluginsdk/abi/v1"
|
||||||
|
"git.dev.alexdunmow.com/block/pluginsdk/datatables"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// datatablesStub implements datatables.DataTables over datatables.* capability
|
||||||
|
// calls. Row payloads cross as JSON bytes.
|
||||||
|
type datatablesStub struct{ base }
|
||||||
|
|
||||||
|
var _ datatables.DataTables = (*datatablesStub)(nil)
|
||||||
|
|
||||||
|
func (s *datatablesStub) GetTableByKey(ctx context.Context, tableKey string) (*datatables.Table, error) {
|
||||||
|
resp := &abiv1.DatatablesGetTableByKeyResponse{}
|
||||||
|
req := &abiv1.DatatablesGetTableByKeyRequest{TableKey: tableKey}
|
||||||
|
if err := s.invoke(ctx, "get_table_by_key", req, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dataTableFromProto(resp.GetTable()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *datatablesStub) GetRow(ctx context.Context, rowID uuid.UUID) (*datatables.Row, error) {
|
||||||
|
resp := &abiv1.DatatablesGetRowResponse{}
|
||||||
|
req := &abiv1.DatatablesGetRowRequest{RowId: rowID.String()}
|
||||||
|
if err := s.invoke(ctx, "get_row", req, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dataTableRowFromProto(resp.GetRow()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *datatablesStub) ListRows(ctx context.Context, tableID uuid.UUID, limit, offset int32) ([]datatables.Row, error) {
|
||||||
|
resp := &abiv1.DatatablesListRowsResponse{}
|
||||||
|
req := &abiv1.DatatablesListRowsRequest{TableId: tableID.String(), Limit: limit, Offset: offset}
|
||||||
|
if err := s.invoke(ctx, "list_rows", req, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rows := make([]datatables.Row, 0, len(resp.GetRows()))
|
||||||
|
for _, r := range resp.GetRows() {
|
||||||
|
if row := dataTableRowFromProto(r); row != nil {
|
||||||
|
rows = append(rows, *row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *datatablesStub) CreateRow(ctx context.Context, tableID uuid.UUID, dataJSON []byte) (*datatables.Row, error) {
|
||||||
|
resp := &abiv1.DatatablesCreateRowResponse{}
|
||||||
|
req := &abiv1.DatatablesCreateRowRequest{TableId: tableID.String(), DataJson: dataJSON}
|
||||||
|
if err := s.invoke(ctx, "create_row", req, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dataTableRowFromProto(resp.GetRow()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *datatablesStub) UpdateRowData(ctx context.Context, rowID uuid.UUID, dataJSON []byte) (*datatables.Row, error) {
|
||||||
|
resp := &abiv1.DatatablesUpdateRowDataResponse{}
|
||||||
|
req := &abiv1.DatatablesUpdateRowDataRequest{RowId: rowID.String(), DataJson: dataJSON}
|
||||||
|
if err := s.invoke(ctx, "update_row_data", req, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dataTableRowFromProto(resp.GetRow()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *datatablesStub) FindRowByField(ctx context.Context, tableID uuid.UUID, field, value string) (*datatables.Row, error) {
|
||||||
|
resp := &abiv1.DatatablesFindRowByFieldResponse{}
|
||||||
|
req := &abiv1.DatatablesFindRowByFieldRequest{TableId: tableID.String(), Field: field, Value: value}
|
||||||
|
if err := s.invoke(ctx, "find_row_by_field", req, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dataTableRowFromProto(resp.GetRow()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataTableFromProto(t *abiv1.DataTableInfo) *datatables.Table {
|
||||||
|
if t == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
id, _ := uuid.Parse(t.GetId())
|
||||||
|
return &datatables.Table{
|
||||||
|
ID: id,
|
||||||
|
TableKey: t.GetTableKey(),
|
||||||
|
Name: t.GetName(),
|
||||||
|
RowCount: t.GetRowCount(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataTableRowFromProto(r *abiv1.DataTableRowInfo) *datatables.Row {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
id, _ := uuid.Parse(r.GetId())
|
||||||
|
tableID, _ := uuid.Parse(r.GetTableId())
|
||||||
|
return &datatables.Row{
|
||||||
|
ID: id,
|
||||||
|
TableID: tableID,
|
||||||
|
DataJSON: r.GetDataJson(),
|
||||||
|
SortOrder: r.GetSortOrder(),
|
||||||
|
}
|
||||||
|
}
|
||||||
2
plugin/wasmguest/caps/testdata/golden/datatables_create_row_req.pb
vendored
Normal file
2
plugin/wasmguest/caps/testdata/golden/datatables_create_row_req.pb
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa{"name":"New"}
|
||||||
3
plugin/wasmguest/caps/testdata/golden/datatables_create_row_resp.pb
vendored
Normal file
3
plugin/wasmguest/caps/testdata/golden/datatables_create_row_resp.pb
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
\
|
||||||
|
$bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa{"name":"New"}
|
||||||
2
plugin/wasmguest/caps/testdata/golden/datatables_find_row_by_field_miss_req.pb
vendored
Normal file
2
plugin/wasmguest/caps/testdata/golden/datatables_find_row_by_field_miss_req.pb
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaagoogle_place_idmissing
|
||||||
0
plugin/wasmguest/caps/testdata/golden/datatables_find_row_by_field_miss_resp.pb
vendored
Normal file
0
plugin/wasmguest/caps/testdata/golden/datatables_find_row_by_field_miss_resp.pb
vendored
Normal file
2
plugin/wasmguest/caps/testdata/golden/datatables_find_row_by_field_req.pb
vendored
Normal file
2
plugin/wasmguest/caps/testdata/golden/datatables_find_row_by_field_req.pb
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaagoogle_place_idabc
|
||||||
3
plugin/wasmguest/caps/testdata/golden/datatables_find_row_by_field_resp.pb
vendored
Normal file
3
plugin/wasmguest/caps/testdata/golden/datatables_find_row_by_field_resp.pb
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
g
|
||||||
|
$bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa{"google_place_id":"abc"}
|
||||||
2
plugin/wasmguest/caps/testdata/golden/datatables_get_row_req.pb
vendored
Normal file
2
plugin/wasmguest/caps/testdata/golden/datatables_get_row_req.pb
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
$bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb
|
||||||
3
plugin/wasmguest/caps/testdata/golden/datatables_get_row_resp.pb
vendored
Normal file
3
plugin/wasmguest/caps/testdata/golden/datatables_get_row_resp.pb
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
h
|
||||||
|
$bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa{"name":"Whiteman Park"}
|
||||||
2
plugin/wasmguest/caps/testdata/golden/datatables_get_table_by_key_req.pb
vendored
Normal file
2
plugin/wasmguest/caps/testdata/golden/datatables_get_table_by_key_req.pb
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
playgrounds
|
||||||
3
plugin/wasmguest/caps/testdata/golden/datatables_get_table_by_key_resp.pb
vendored
Normal file
3
plugin/wasmguest/caps/testdata/golden/datatables_get_table_by_key_resp.pb
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
C
|
||||||
|
$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaaplaygroundsPlaygrounds ¦
|
||||||
2
plugin/wasmguest/caps/testdata/golden/datatables_list_rows_req.pb
vendored
Normal file
2
plugin/wasmguest/caps/testdata/golden/datatables_list_rows_req.pb
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaad
|
||||||
5
plugin/wasmguest/caps/testdata/golden/datatables_list_rows_resp.pb
vendored
Normal file
5
plugin/wasmguest/caps/testdata/golden/datatables_list_rows_resp.pb
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
Z
|
||||||
|
$bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa{"name":"A"}
|
||||||
|
\
|
||||||
|
$44444444-4444-4444-4444-444444444444$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa{"name":"B"}
|
||||||
2
plugin/wasmguest/caps/testdata/golden/datatables_update_row_data_req.pb
vendored
Normal file
2
plugin/wasmguest/caps/testdata/golden/datatables_update_row_data_req.pb
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
$bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb{"name":"Updated"}
|
||||||
3
plugin/wasmguest/caps/testdata/golden/datatables_update_row_data_resp.pb
vendored
Normal file
3
plugin/wasmguest/caps/testdata/golden/datatables_update_row_data_resp.pb
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
b
|
||||||
|
$bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb$aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa{"name":"Updated"}
|
||||||
Loading…
x
Reference in New Issue
Block a user