This post utilizes our new MCP Server for the Oracle Database.
Windsurf is a popular Agentic IDE that supports MCP Servers, and is currently offering access to the ChatGPT 5 Language Learning Model (LLM.)
Inside of Windsurf you can use the Cascade agent, “Dense reasoning over implicit user intent
Cascade tracks all your actions—edits, commands, conversation history, clipboard, terminal commands etc —to infer intent and adapt in real time, helping you stay in flow without repeating yourself.“
The MCP Server config and Tool display comes together in Windsurf like so –

Let’s build a schema, together.
prompt: I’m starting a new project, where we will build a content management system. I need help with the data model for my Oracle Database.
I’m using version 23.9, so please use appropriate DDL as show in this tutorial https://blogs.oracle.com/coretec/post/oracle-database-23c-free-developer-sql
Create tables for the following entities, with proper foreign key constraints, comments, and data types.
Categories – for dividing content by topic or channel
Posts – the actual story or content Authors – one or more people responsible for authoring a post
Media – rich media to be included in an post, primarily video and images
Tags – metadata labels to mark a post for a specific topic, a post can have one or more tags Comments – to allow readers to share their questions and comments on a post
Implement this schema using my WINDY database connection.
That’s literally what I have presented to the Cascade agent, inside of Windsurf.
Implement this schema using my WINDY database connection
Let’s start at the end, first.
In SQLcl, I have created a user, and defined a connection that can be used by the MCP Clients.
SQL> create user wind identified by surfer;
User WIND created.
SQL> grant db_developer_role to wind;
Grant succeeded.
SQL> grant connect, resource to wind;
Grant succeeded.
SQL> ALTER USER "WIND" QUOTA 5M ON "USERS";
User "WIND" altered.
SQL> disconnect
Disconnected from Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.7.0.25.01
SQL> conn -save windy -savepwd wind/surfer@localhost:1521/freepdb1
Name: windy
Connect String: localhost:1521/freepdb1
User: wind
Password: ******
Connected.Windsurf and it’s agent, Cascade, will never see any of these connection properties. All that it will know, is that the name of the connection is ‘windy’ and that it can be used to make a connection.
The MCP Server (SQLcl) will get spun up by Windsurf as needed, running on my machine, for use only by me, via Cascade.
Thought Process / Planning
I believe this plan driven workflow is one reason why Windsurf has found early success. We get a Markdown ‘plan’ file created, and we can see as the Agent moves through the plan, accomplishing steps, step-by-step.
We also get to see it ‘planning’ and ‘thinking’ as it goes.

From looking at the ‘thought process,’ it hasn’t used the blog post I referenced, yet.
The model has apparently already been trained on 23ai SQL syntaxes like “CREATE TABLE IF NOT EXISTS…,” – GREAT.
As I go through all of the thought processes and plans, I can see that it’s using many resources on docs.oracle.com, but not the blog post I gave it. I probably didn’t use the right prompt syntax or ‘keywords.’
Failure doesn’t mean, we stop. We fail FORWARD.
When it’s ready to run the DDL it has generated, it tries to make a connection. But, it takes my connection request, literally. It tried to make a connection named “WINDY,” and failed.

But it didn’t stop. It ‘reasoned’ that it could get a list of connections and find what I was referring to. Turns out that “windy” is pretty close to “WINDY,” so it was happy to plod along to the next step in its plan.
Generating the schema and deploying it.
It generated a script, was smart enough to put it all through the ‘run-sql’ tool in a single go. Nice.
The ‘thought’ process around generating the schema DDL looks like this:
I've established the connection, and now I need to create several tables: Categories, Posts, Authors, Media, Tags, and Comments, along with junction tables for the many-to-many relationships. I want to ensure I apply Oracle 23c features, checking for "CREATE IF NOT EXISTS" and related clauses. I should also include comments on the tables and define data types properly, using VARCHAR2 with length semantics, timestamps, and constraints for better organization and uniqueness in the database structure.
Setting up database constraints
I want to add a status enum through a CHECK constraint, and I'm considering row-level security, though it might not be necessary. I'll use the mcp0_run-sql tool to execute the SQL, ensuring every query includes a comment with the model name. I need to craft multiple statements, so I'll ensure semicolons separate them and might use a BEGIN...END block. For the DDL, I’ll create a categories table with an identity column for category_id, along with attributes like name, slug, description, and timestamps.
Defining the Posts table
I’m setting up a foreign key on the parent_id, which references categories and will set to null on delete. For the Posts table, I’ll include a post_id generated as an identity, along with a title, slug, content, and excerpt. I'll ensure a category_id is linked, and the status is constrained to values like 'draft', 'published', and 'archived.' The timestamps for created_at and published_at will also be included. However, I’m reconsidering whether created_by and updated_by are necessary since we have a many-to-many relationship with Authors.
Finalizing table designs
I’m simplifying the Posts table by omitting the created_by field. The foreign key for category_id will reference categories and set to null on delete. I'll ensure the slug is unique and set up an index on status, category_id, and published_at. For the Authors table, I'll define the identity columns along with display names and unique emails.
In the Post_Authors table, I'll set primary keys and foreign keys with cascading deletes. For Tags, the same unique rules will apply, and I’ll ensure the Media table allows various media types with structured attributes. Finally, Comments will track statuses and link back to posts.
Preparing to run SQL script
I need to ensure that cascading deletes are set on foreign keys, which might delete child records. I'll index post_id, status, and created_at for efficiency. To avoid errors when re-running the script, I'll use CREATE TABLE IF NOT EXISTS. Adding "ON DELETE CASCADE" or "SET NULL" must be supported on foreign keys, and I'll include comments via COMMENT ON.
Oh, and I need to add a comment immediately after the main SQL keywords, which feels tedious but is necessary according to requirements. Let’s prepare to run the mcp0_run-sql with the complete script.
It’s complaining about my requirements! When I asked for comments, I mean table and column comments, not comments in the DDL scripts, but let’s see where we end up.
Schema created, now it’s going to test and report
It’s not happy that the script executed. It wants to now query the dictionary (USER_TABLES) to make sure all the tables it created, are actually IN the database.

And if I ‘look left,’ I can see in my Markdown planning page being updated to reflect it’s progress –

Let’s check for ourselves
Poking into the WIND schema, I can see some tables, and they appear to be close to what I asked for. The LLM did more normalization than I asked for even, POSTS, POST_AUTHORS, and AUTHORS tables. POSTS, POST_TAGS, and TAGS, cool.

My columns are commented. And let’s look at the the model, and how it was implemented for this table.
CREATE TABLE "POSTS"
( "POST_ID" NUMBER GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"TITLE" VARCHAR2(200 BYTE) NOT NULL ENABLE,
"SLUG" VARCHAR2(220 BYTE) NOT NULL ENABLE,
"CONTENT" CLOB NOT NULL ENABLE,
"EXCERPT" VARCHAR2(1000 BYTE),
"CATEGORY_ID" NUMBER,
"STATUS" VARCHAR2(20 BYTE) NOT NULL ENABLE,
"PUBLISHED_AT" TIMESTAMP (6),
"CREATED_AT" TIMESTAMP (6) DEFAULT SYSTIMESTAMP NOT NULL ENABLE,
"UPDATED_AT" TIMESTAMP (6)
) ;
ALTER TABLE "POSTS" ADD CONSTRAINT "CK_POSTS_STATUS" CHECK (status IN ('draft','published','archived')) ENABLE;
ALTER TABLE "POSTS" ADD PRIMARY KEY ("POST_ID")
USING INDEX ENABLE;
ALTER TABLE "POSTS" ADD CONSTRAINT "UQ_POSTS_SLUG" UNIQUE ("SLUG")
USING INDEX ENABLE;
ALTER TABLE "POSTS" ADD CONSTRAINT "FK_POSTS_CATEGORY" FOREIGN KEY ("CATEGORY_ID")
REFERENCES "CATEGORIES" ("CATEGORY_ID") ON DELETE SET NULL ENABLE;
COMMENT ON COLUMN "POSTS"."POST_ID" IS 'Surrogate primary key';
COMMENT ON COLUMN "POSTS"."TITLE" IS 'Post title';
COMMENT ON COLUMN "POSTS"."SLUG" IS 'URL-friendly unique identifier';
COMMENT ON COLUMN "POSTS"."CONTENT" IS 'Primary content body';
COMMENT ON COLUMN "POSTS"."EXCERPT" IS 'Optional summary';
COMMENT ON COLUMN "POSTS"."CATEGORY_ID" IS 'Optional category for the post';
COMMENT ON COLUMN "POSTS"."STATUS" IS 'Workflow status: draft/published/archived';
COMMENT ON COLUMN "POSTS"."PUBLISHED_AT" IS 'Timestamp when published';
COMMENT ON COLUMN "POSTS"."CREATED_AT" IS 'Creation timestamp';
COMMENT ON COLUMN "POSTS"."UPDATED_AT" IS 'Last update timestamp';
COMMENT ON TABLE "POSTS" IS 'Posts store the main content stories';
CREATE INDEX "IX_POSTS_CATEGORY" ON "POSTS" ("CATEGORY_ID")
;
CREATE INDEX "IX_POSTS_STATUS" ON "POSTS" ("STATUS")
;
CREATE INDEX "IX_POSTS_PUBLISHED_AT" ON "POSTS" ("PUBLISHED_AT")
;We used an IDENTITY column to manage the primary key, I’m OK with that.
We have foreign keys, yes!
Post contents are stored in a CLOB, and that is appropriate.
We’re using TIMESTAMPS for temporals, good good good!
Post statuses are hard coded into a CHECK CONSTRAINT, that’s…OK, sure.
Let’s visualize the schema
Using SQL Developer Web, this is what the tables look like. Note this feature will be coming fairly soon to our VS Code Extension, stay tuned!

But wait, we’re not done!
Windsurf is offering to do, more.

Ok, so it inserted a post, across all the necessary tables. Let’s see what that looks like.

And, who was the author?
SQL> select *
2* from authors;
AUTHOR_ID DISPLAY_NAME EMAIL BIO PROFILE_IMAGE_URL CREATED_AT UPDATED_AT
____________ _______________ ________________________ ______________________________________________________ ____________________ __________________________________ _____________
1 Kris Rice [email protected] Kris Rice is a database and developer tools expert. 18-AUG-25 06.58.20.705151000 PM
SQL> Checks out!
I wonder if our post has any comments, and if so, what was left for Kris to glean from?
SQL> select author_name, content, status
2* from comments;
AUTHOR_NAME CONTENT STATUS
______________ ________________________________________________________ ___________
Jane Reader Great article! Looking forward to more on 23ai + MCP. approved
SQL> We’re also looking forward to more!
This is 23ai, don’t we have like these JSON Relational Duality Views?
Yes, and Windsurf is offering to create one for me! But, I found the following:
- left on it’s own, it creates boring, useless duality views
- with a prompt, it tried creating a useful one, a single JSON doc, with all the data I needed
- it failed, repeatedly, until I told it to read/train itself on our Docs using the GraphQL syntax
“It’s easier than this. Train on this document – it introduces GraphQL syntax, making it easy to join our tables in the duality view … link -> - it took 2-3 iterations AFTER it got the GraphQL syntax going, for it to see how to properly use it
But then, I ended up with this –

Two parting thoughts on Windsurf and Cascade
It would be great to see if it’s true to its word about learning from our experience. Does all this work get ‘remembered’ the next time I want to add a Duality View? Or if I want to amend the data model, will it account for what it’s already done?
I wouldn’t use this anywhere near production.
At least, not until I learn how to properly use Cascade’s workflows.
The Agent interface ran right through the MCP Tools invocations. No prompts for permission or checking.
And when I asked Windsurf how to get it to stop and ask for permission, it generated fake docs and settings for me to look at. Or at least, that’s the best I could make of it. So if you’re reading this and I’m an IDIOT, please show me where this ‘setting’ is:
Toggle “Require approval before using MCP tools” (global).
The recording from our session
24 different MCP Tool interactions, the bulk of these are the LLM trying to get ‘the hang’ of Duality Views syntax.

Show me my work!
This is another fun bit. As the Agent was doing all of this work for me, directly in the database, it was NOT keeping a local ‘copy’ of the SQL/DDL it was using to create my objects.
I found this out when I asked Cascade to generate a local file for me.
prompt: please generate a local file containing all of the final versions of the object scripts used to buid our CMS schema
Cascade came back with an, ‘oops’ we don’t have that, we’ll have to regenerate it, and followed that with a mcp tool request on run-sql to use DBMS_METADATA to get it.
Cheeky…maybe it’s how I chose to to direct Cascade, but I would have much more enjoyed seeing local files generated that I could see as we went, vs me having to reverse engineer the database afterwards. I could have then had a rolling set of DIFFs to see how the scripts were changing over time based on the LLM ‘learning’ and me interjecting with feedback.

So it did that, and even told me how to run it, with SQLcl.

Here’s our script.
-- CMS Schema DDL Export
-- Generated by Cascade on 2025-08-19T08:02:17-04:00
-- Contains final object scripts for tables and views (including duality views)
-- Note: Run as the WIND schema owner (or adjust schema qualifiers as needed).
-------------------------------------------------------------------------------
-- TABLES
-------------------------------------------------------------------------------
CREATE TABLE "WIND"."AUTHORS"
( "AUTHOR_ID" NUMBER GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"DISPLAY_NAME" VARCHAR2(150) NOT NULL ENABLE,
"EMAIL" VARCHAR2(254) NOT NULL ENABLE,
"BIO" CLOB,
"PROFILE_IMAGE_URL" VARCHAR2(500),
"CREATED_AT" TIMESTAMP (6) DEFAULT SYSTIMESTAMP NOT NULL ENABLE,
"UPDATED_AT" TIMESTAMP (6),
PRIMARY KEY ("AUTHOR_ID")
USING INDEX ENABLE,
CONSTRAINT "UQ_AUTHORS_EMAIL" UNIQUE ("EMAIL")
USING INDEX ENABLE
) ;
CREATE TABLE "WIND"."CATEGORIES"
( "CATEGORY_ID" NUMBER GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"NAME" VARCHAR2(100) NOT NULL ENABLE,
"SLUG" VARCHAR2(120) NOT NULL ENABLE,
"DESCRIPTION" VARCHAR2(4000),
"PARENT_ID" NUMBER,
"CREATED_AT" TIMESTAMP (6) DEFAULT SYSTIMESTAMP NOT NULL ENABLE,
"UPDATED_AT" TIMESTAMP (6),
PRIMARY KEY ("CATEGORY_ID")
USING INDEX ENABLE,
CONSTRAINT "UQ_CATEGORIES_SLUG" UNIQUE ("SLUG")
USING INDEX ENABLE,
CONSTRAINT "FK_CATEGORIES_PARENT" FOREIGN KEY ("PARENT_ID")
REFERENCES "WIND"."CATEGORIES" ("CATEGORY_ID") ON DELETE SET NULL ENABLE
) ;
CREATE TABLE "WIND"."COMMENTS"
( "COMMENT_ID" NUMBER GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"POST_ID" NUMBER NOT NULL ENABLE,
"PARENT_ID" NUMBER,
"AUTHOR_NAME" VARCHAR2(150) NOT NULL ENABLE,
"AUTHOR_EMAIL" VARCHAR2(254),
"CONTENT" CLOB NOT NULL ENABLE,
"STATUS" VARCHAR2(20) NOT NULL ENABLE,
"CREATED_AT" TIMESTAMP (6) DEFAULT SYSTIMESTAMP NOT NULL ENABLE,
"UPDATED_AT" TIMESTAMP (6),
CONSTRAINT "CK_COMMENTS_STATUS" CHECK (status IN ('pending','approved','spam','deleted')) ENABLE,
PRIMARY KEY ("COMMENT_ID")
USING INDEX ENABLE,
CONSTRAINT "FK_COMMENTS_POST" FOREIGN KEY ("POST_ID")
REFERENCES "WIND"."POSTS" ("POST_ID") ON DELETE CASCADE ENABLE,
CONSTRAINT "FK_COMMENTS_PARENT" FOREIGN KEY ("PARENT_ID")
REFERENCES "WIND"."COMMENTS" ("COMMENT_ID") ON DELETE CASCADE ENABLE
) ;
CREATE TABLE "WIND"."MEDIA"
( "MEDIA_ID" NUMBER GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"POST_ID" NUMBER NOT NULL ENABLE,
"MEDIA_TYPE" VARCHAR2(20) NOT NULL ENABLE,
"URL" VARCHAR2(1000) NOT NULL ENABLE,
"TITLE" VARCHAR2(200),
"ALT_TEXT" VARCHAR2(500),
"CAPTION" VARCHAR2(1000),
"POSITION" NUMBER,
"CREATED_AT" TIMESTAMP (6) DEFAULT SYSTIMESTAMP NOT NULL ENABLE,
CONSTRAINT "CK_MEDIA_TYPE" CHECK (media_type IN ('image','video','audio','other')) ENABLE,
PRIMARY KEY ("MEDIA_ID")
USING INDEX ENABLE,
CONSTRAINT "FK_MEDIA_POST" FOREIGN KEY ("POST_ID")
REFERENCES "WIND"."POSTS" ("POST_ID") ON DELETE CASCADE ENABLE
) ;
CREATE TABLE "WIND"."POSTS"
( "POST_ID" NUMBER GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"TITLE" VARCHAR2(200) NOT NULL ENABLE,
"SLUG" VARCHAR2(220) NOT NULL ENABLE,
"CONTENT" CLOB NOT NULL ENABLE,
"EXCERPT" VARCHAR2(1000),
"CATEGORY_ID" NUMBER,
"STATUS" VARCHAR2(20) NOT NULL ENABLE,
"PUBLISHED_AT" TIMESTAMP (6),
"CREATED_AT" TIMESTAMP (6) DEFAULT SYSTIMESTAMP NOT NULL ENABLE,
"UPDATED_AT" TIMESTAMP (6),
CONSTRAINT "CK_POSTS_STATUS" CHECK (status IN ('draft','published','archived')) ENABLE,
PRIMARY KEY ("POST_ID")
USING INDEX ENABLE,
CONSTRAINT "UQ_POSTS_SLUG" UNIQUE ("SLUG")
USING INDEX ENABLE,
CONSTRAINT "FK_POSTS_CATEGORY" FOREIGN KEY ("CATEGORY_ID")
REFERENCES "WIND"."CATEGORIES" ("CATEGORY_ID") ON DELETE SET NULL ENABLE
) ;
CREATE TABLE "WIND"."POST_AUTHORS"
( "POST_ID" NUMBER NOT NULL ENABLE,
"AUTHOR_ID" NUMBER NOT NULL ENABLE,
"ROLE" VARCHAR2(50),
PRIMARY KEY ("POST_ID", "AUTHOR_ID")
USING INDEX ENABLE,
CONSTRAINT "FK_POST_AUTHORS_POST" FOREIGN KEY ("POST_ID")
REFERENCES "WIND"."POSTS" ("POST_ID") ON DELETE CASCADE ENABLE,
CONSTRAINT "FK_POST_AUTHORS_AUTHOR" FOREIGN KEY ("AUTHOR_ID")
REFERENCES "WIND"."AUTHORS" ("AUTHOR_ID") ON DELETE CASCADE ENABLE
) ;
CREATE TABLE "WIND"."POST_TAGS"
( "POST_ID" NUMBER NOT NULL ENABLE,
"TAG_ID" NUMBER NOT NULL ENABLE,
PRIMARY KEY ("POST_ID", "TAG_ID")
USING INDEX ENABLE,
CONSTRAINT "FK_POST_TAGS_POST" FOREIGN KEY ("POST_ID")
REFERENCES "WIND"."POSTS" ("POST_ID") ON DELETE CASCADE ENABLE,
CONSTRAINT "FK_POST_TAGS_TAG" FOREIGN KEY ("TAG_ID")
REFERENCES "WIND"."TAGS" ("TAG_ID") ON DELETE CASCADE ENABLE
) ;
CREATE TABLE "WIND"."TAGS"
( "TAG_ID" NUMBER GENERATED BY DEFAULT AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"NAME" VARCHAR2(100) NOT NULL ENABLE,
"SLUG" VARCHAR2(120) NOT NULL ENABLE,
"DESCRIPTION" VARCHAR2(4000),
"CREATED_AT" TIMESTAMP (6) DEFAULT SYSTIMESTAMP NOT NULL ENABLE,
"UPDATED_AT" TIMESTAMP (6),
PRIMARY KEY ("TAG_ID")
USING INDEX ENABLE,
CONSTRAINT "UQ_TAGS_SLUG" UNIQUE ("SLUG")
USING INDEX ENABLE,
CONSTRAINT "UQ_TAGS_NAME" UNIQUE ("NAME")
USING INDEX ENABLE
) ;
-------------------------------------------------------------------------------
-- VIEWS (Standard + Duality Views)
-------------------------------------------------------------------------------
CREATE OR REPLACE FORCE EDITIONABLE VIEW "WIND"."V_POSTS_TOP" ("POST_ID", "TITLE", "SLUG", "EXCERPT", "STATUS", "PUBLISHED_AT", "CREATED_AT", "UPDATED_AT", "CATEGORY_ID", "CATEGORY_NAME", "CATEGORY_SLUG") AS
SELECT
p.post_id,
p.title,
p.slug,
p.excerpt,
p.status,
p.published_at,
p.created_at,
p.updated_at,
p.category_id,
c.name AS category_name,
c.slug AS category_slug
FROM posts p
LEFT JOIN categories c ON c.category_id = p.category_id;
CREATE OR REPLACE FORCE EDITIONABLE JSON RELATIONAL DUALITY VIEW "WIND"."POSTS_DV" AS
SELECT JSON {
'_id' : p.post_id,
'title' : p.title,
'slug' : p.slug,
'excerpt' : p.excerpt,
'status' : p.status,
'published_at' : p.published_at,
'created_at' : p.created_at,
'updated_at' : p.updated_at,
'category' : (
SELECT JSON {
'_id' : c.category_id,
'name' : c.name,
'slug' : c.slug
}
FROM categories c
WHERE c.category_id = p.category_id
)
}
FROM posts p;
CREATE OR REPLACE FORCE EDITIONABLE JSON RELATIONAL DUALITY VIEW "WIND"."POSTS_FULL_DV" AS
posts @insert @update @delete {
_id : post_id,
title : title,
slug : slug,
excerpt : excerpt,
status : status,
published_at : published_at,
created_at : created_at,
updated_at : updated_at,
category : categories @noinsert @noupdate @nodelete { _id : category_id, name : name, slug : slug },
authors : post_authors @insert @update @delete [
{ postId : post_id, authorId : author_id, role : role,
author : authors @noinsert @noupdate @nodelete { _id : author_id, name : display_name } }
],
tags : post_tags @insert @delete [
{ postId : post_id, tagId : tag_id,
tag : tags @noinsert @noupdate @nodelete { _id : tag_id, name : name, slug : slug } }
],
comments : comments @insert @update @delete [
{ _id : comment_id, parent_id : parent_id, author_name : author_name,
author_email : author_email, content : content, status : status,
created_at : created_at, updated_at : updated_at }
]
};
CREATE OR REPLACE FORCE EDITIONABLE JSON RELATIONAL DUALITY VIEW "WIND"."AUTHORS_FULL_DV" AS
authors @insert @update @delete {
_id : author_id,
name : display_name,
email : email,
bio : bio,
created_at : created_at,
updated_at : updated_at,
posts : post_authors @insert @delete [
{ postId : post_id, authorId : author_id, role : role,
post : posts @noinsert @noupdate @nodelete {
_id : post_id,
title : title,
slug : slug,
status : status,
published_at : published_at,
category : categories @noinsert @noupdate @nodelete { _id : category_id, name : name, slug : slug }
}
}
]
};
CREATE OR REPLACE FORCE EDITIONABLE JSON RELATIONAL DUALITY VIEW "WIND"."CATEGORIES_FULL_DV" AS
categories @insert @update @delete {
_id : category_id,
name : name,
slug : slug,
posts : posts [
{ _id : post_id, title : title, slug : slug, status : status,
authors : post_authors { postId : post_id, authorId : author_id, role : role,
author : authors { _id : author_id, name : display_name } },
tags : post_tags { postId : post_id, tagId : tag_id,
tag : tags { _id : tag_id, name : name, slug : slug } }
}
]
};