Add OCI NoSQL Database: tables, rows, indexes - #424
Conversation
Implements OCI NoSQL Database against the portable database driver: providers/oci/nosql holds the mock over memstore, server/oci/nosql the /20190828 wire handler. Tables are created from a DDL statement rather than a key list, so the provider parses CREATE TABLE and ALTER TABLE — scalar and JSON column types, NOT NULL, DEFAULT, PRIMARY KEY with an optional SHARD, USING TTL in days, and ADD/DROP on a non-key column. Everything else is refused with the construct named: primary keys wider than the portable partition/sort key pair, composite shard keys, structured column types, generated and MR_COUNTER modifiers, TTL in hours, MODIFY and schema freezing, and JSON-path index keys. Tables carry an OCID, a compartment recorded at create and capacity limits validated against their mode; both list routes require compartmentId. Table and index mutations record a work request and stamp opc-work-request-id. Rows are addressed by typed primary key columns and written synchronously. The query endpoint runs SELECT * and DELETE FROM with AND-ed equality conditions — the REST API has no MultiDelete, so DELETE FROM ... WHERE is the multi-row delete. Table usage and the prepared-statement endpoints answer 501 naming the gap. OCI NoSQL publishes no change stream, so the portable stream operations report Unimplemented rather than an empty iterator. The OCI-only surface is a consumer-side Extras interface in server/oci/nosql with its value types in providers/oci/nosql; nothing is added to services/database/driver. Closes #412
NitinKumar004
left a comment
There was a problem hiding this comment.
Review notes
Real data-plane engine (per #427): N/A.
Findings
Medium · real-engine — Table names are globally unique, not per-compartment
providers/oci/nosql/nosql.go:417
If a user creates table "orders" in compartment A and then "orders" in compartment B -> the second CreateTable returns 409 AlreadyExists, because table names are a global key rather than compartment-scoped; real OCI scopes NoSQL table names per compartment and both creates succeed, so a multi-compartment SDK/CLI test that reuses a table name across compartments breaks against the emulator only.
m.tables is keyed by table name globally (nosql.go:175); newTable rejects with AlreadyExists on m.tables.Has(name) (nosql.go:417), and CreateOCITable checks m.tables.Get(d.Table) irrespective of spec.CompartmentID (table_extras.go:38-44). resolve()/lookup() also address tables by name globally.
Low · coverage — Portable Query/Scan operators and typed coercion below the 90% coverage pillar
providers/oci/nosql/rows.go:324
If a user issues a portable Query/Scan with a relational sort condition (>, BETWEEN) or stores a LONG/FLOAT/BOOLEAN-typed row -> the ordering (compareOrdering/compareStrings) and coercion (parseTyped/convertTyped) execute for the first time in production with no test guarding them, so a comparison- or coercion-logic regression would ship undetected.
go test -cover: provider 85.8%, server 83.4% (both < 90%). compareOrdering (rows.go:324) 0%, compareStrings (rows.go:341) 0%, compareOp (rows.go:306) 28.6%, parseTyped (row_extras.go:211) 35.7%, convertTyped (row_extras.go:242) 36.8%, SetMonitoring (nosql.go:194) 0%. Query tests exercise only SortOp "="; <, >, <=, >=, BETWEEN and CONTAINS/BEGINS_WITH ordering are never run.
Low · wire-fidelity — No oci-go-sdk SDK-compat test for the handler
server/oci/nosql/handler_test.go:94
If the real oci-go-sdk nosql client shapes a request/response field differently than the hand-modeled types.go structs (e.g. a body vs query-parameter for the Query limit, or a header the SDK requires) -> the divergence is not caught by the current tests, so a genuine client could fail at a step the httptest cases pass; adding one SDK create/get/query round-trip would close this.
handler_test.go drives the handler via raw httptest requests only; the only reference to github.com/oracle/oci-go-sdk is the package doc comment in handler.go. oci-conventions.md calls an SDK round-trip against httptest.NewServer "the strongest evidence the handler is right" (recommended, not required).
Summary
databasedriver.CreateTabletakes a SQL-ish statement rather than an attribute list.services/database/driver; OCI-only behaviour is a consumer-sideExtrasinterface, per Move OCI-only capabilities out of shared driver packages #393.Closes #412. Part of #376.
Changes
providers/oci/nosql/—Mockovermemstoreimplementingdriver.Database, guarded by async.RWMutex, plus the DDL parser and a query evaluator.server/oci/nosql/— the/20190828/surface.providers/oci/oci.goandserver/oci/oci.go.Operations: tables (Create/List/Get/Update/Delete/ChangeCompartment), indexes (Create/List/Get/Delete), rows (GetRow/UpdateRow/DeleteRow), and Query. All 24 portable
Databasemethods implemented.DDL — what is parsed, what is refused
Parsed:
CREATE TABLEandALTER TABLE— scalar andJSONtypes,NOT NULL,DEFAULT,PRIMARY KEYwith optionalSHARD,USING TTL <n> DAYS,ADD/DROPon non-key columns,IF NOT EXISTS.Refused by name, never silently accepted:
ARRAY/MAP/RECORD/ENUMMR_COUNTER/UUIDmodifiersUSING TTL … HOURSSchemareports TTL only in daysMODIFY, schema freezing, JSON-path index keysORDER BY, range conditionsJudgement calls
UpdateStreamConfig/GetStreamRecordsreturnUnimplementedrather than an empty iterator. Noted indocs/services.md.DELETE FROM … WHEREover/query— OCI's REST API has noMultiDeleteoperation; this is the real mechanism.ListIndexesrequirescompartmentIdalthough real OCI marks it optional, so no list is ever unscoped. Documented./tables/{id}/usageand/query/prepare,/query/summarize.usageis omitted from row and query responses for the same reason — zeros would read as real telemetry.Provider Coverage
Checklist
go test ./...) — exit 0, 272 packagesgolangci-lint run --timeout=9m) — 0 issuescloudemu_test.go— driver + handler tests insteadTest Plan
Coverage leak check clean: no OCI operation in
docs/coverage/{aws,azure,gcp}/*.md;git diff development -- services/empty.End-to-end on a running server (port 4613):
A note on parallel worktrees
An earlier run of this branch failed
cmd/cloudemu TestServeOutOfProcess. It is not this change —cmd/cloudemuis untouched by the diff. Six Wave 2 worktrees were running their suites concurrently and that test contends on the shared~/.cloudemudaemon lock. Verified: with nothing else running it passes, and the full suite is exit 0. Worth knowing as shared-state fragility whenever suites run in parallel.