diff --git a/content/docs/references/data/field.mdx b/content/docs/references/data/field.mdx index 43975793d..f59b1a883 100644 --- a/content/docs/references/data/field.mdx +++ b/content/docs/references/data/field.mdx @@ -12,8 +12,8 @@ description: Field protocol schemas ## TypeScript Usage ```typescript -import { AddressSchema, CurrencyConfigSchema, CurrencyValueSchema, FieldSchema, FieldTypeSchema, FileAttachmentConfigSchema, LocationCoordinatesSchema, SelectOptionSchema, VectorConfigSchema } from '@objectstack/spec/data'; -import type { Address, CurrencyConfig, CurrencyValue, Field, FieldType, FileAttachmentConfig, LocationCoordinates, SelectOption, VectorConfig } from '@objectstack/spec/data'; +import { AddressSchema, ComputedFieldCacheSchema, CurrencyConfigSchema, CurrencyValueSchema, DataQualityRulesSchema, FieldSchema, FieldTypeSchema, FileAttachmentConfigSchema, LocationCoordinatesSchema, SelectOptionSchema, VectorConfigSchema } from '@objectstack/spec/data'; +import type { Address, ComputedFieldCache, CurrencyConfig, CurrencyValue, DataQualityRules, Field, FieldType, FileAttachmentConfig, LocationCoordinates, SelectOption, VectorConfig } from '@objectstack/spec/data'; // Validate data const result = AddressSchema.parse(data); @@ -37,6 +37,18 @@ const result = AddressSchema.parse(data); --- +## ComputedFieldCache + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **enabled** | `boolean` | ✅ | Enable caching for computed field results | +| **ttl** | `number` | ✅ | Cache TTL in seconds (0 = no expiration) | +| **invalidateOn** | `string[]` | ✅ | Field paths that invalidate cache (e.g., ["inventory.quantity", "pricing.base_price"]) | + +--- + ## CurrencyConfig ### Properties @@ -60,6 +72,18 @@ const result = AddressSchema.parse(data); --- +## DataQualityRules + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **uniqueness** | `boolean` | optional | Enforce unique values across all records | +| **completeness** | `number` | optional | Minimum ratio of non-null values (0-1, default: 0 = no requirement) | +| **accuracy** | `object` | optional | Accuracy validation configuration | + +--- + ## Field ### Properties @@ -111,9 +135,15 @@ const result = AddressSchema.parse(data); | **currencyConfig** | `object` | optional | Configuration for currency field type | | **vectorConfig** | `object` | optional | Configuration for vector field type (AI/ML embeddings) | | **fileAttachmentConfig** | `object` | optional | Configuration for file and attachment field types | +| **encryptionConfig** | `object` | optional | Field-level encryption configuration for sensitive data (GDPR/HIPAA/PCI-DSS) | +| **maskingRule** | `object` | optional | Data masking rules for PII protection | +| **auditTrail** | `boolean` | optional | Enable detailed audit trail for this field (tracks all changes with user and timestamp) | +| **dependencies** | `string[]` | optional | Array of field names that this field depends on (for formulas, visibility rules, etc.) | +| **cached** | `object` | optional | Caching configuration for computed/formula fields | +| **dataQuality** | `object` | optional | Data quality validation and monitoring rules | | **hidden** | `boolean` | optional | Hidden from default UI | | **readonly** | `boolean` | optional | Read-only in UI | -| **encryption** | `boolean` | optional | Encrypt at rest | +| **encryption** | `boolean` | optional | Deprecated: Use encryptionConfig for enhanced encryption features. Simple flag for backward compatibility. | | **index** | `boolean` | optional | Create standard database index | | **externalId** | `boolean` | optional | Is external ID for upsert operations | diff --git a/content/docs/references/data/object.mdx b/content/docs/references/data/object.mdx index b341823fc..4dd2e04ab 100644 --- a/content/docs/references/data/object.mdx +++ b/content/docs/references/data/object.mdx @@ -12,25 +12,38 @@ description: Object protocol schemas ## TypeScript Usage ```typescript -import { IndexSchema, ObjectSchema, ObjectCapabilitiesSchema } from '@objectstack/spec/data'; -import type { Index, Object, ObjectCapabilities } from '@objectstack/spec/data'; +import { CDCConfigSchema, IndexSchema, ObjectSchema, ObjectCapabilitiesSchema, PartitioningConfigSchema, SoftDeleteConfigSchema, TenancyConfigSchema, VersioningConfigSchema } from '@objectstack/spec/data'; +import type { CDCConfig, Index, Object, ObjectCapabilities, PartitioningConfig, SoftDeleteConfig, TenancyConfig, VersioningConfig } from '@objectstack/spec/data'; // Validate data -const result = IndexSchema.parse(data); +const result = CDCConfigSchema.parse(data); ``` --- +## CDCConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **enabled** | `boolean` | ✅ | Enable Change Data Capture | +| **events** | `Enum<'insert' \| 'update' \| 'delete'>[]` | ✅ | Event types to capture | +| **destination** | `string` | ✅ | Destination endpoint (e.g., "kafka://topic", "webhook://url") | + +--- + ## Index ### Properties | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **name** | `string` | optional | Index name | +| **name** | `string` | optional | Index name (auto-generated if not provided) | | **fields** | `string[]` | ✅ | Fields included in the index | -| **unique** | `boolean` | optional | Whether the index is unique | -| **type** | `Enum<'btree' \| 'hash' \| 'gin' \| 'gist'>` | optional | Index type (default: btree) | +| **type** | `Enum<'btree' \| 'hash' \| 'gin' \| 'gist' \| 'fulltext'>` | optional | Index algorithm type | +| **unique** | `boolean` | optional | Whether the index enforces uniqueness | +| **partial** | `string` | optional | Partial index condition (SQL WHERE clause for conditional indexes) | --- @@ -53,6 +66,11 @@ const result = IndexSchema.parse(data); | **tableName** | `string` | optional | Physical table/collection name in the target datasource | | **fields** | `Record` | ✅ | Field definitions map | | **indexes** | `object[]` | optional | Database performance indexes | +| **tenancy** | `object` | optional | Multi-tenancy configuration for SaaS applications | +| **softDelete** | `object` | optional | Soft delete (trash/recycle bin) configuration | +| **versioning** | `object` | optional | Record versioning and history tracking configuration | +| **partitioning** | `object` | optional | Table partitioning configuration for performance | +| **cdc** | `object` | optional | Change Data Capture (CDC) configuration for real-time data streaming | | **validations** | `object \| object \| object \| object \| object \| object \| object \| object \| object[]` | optional | Object-level validation rules | | **titleFormat** | `string` | optional | Title expression (e.g. "`{name}` - `{code}`"). Overrides nameField. | | **compactLayout** | `string[]` | optional | Primary fields for hover/cards/lookups | @@ -78,3 +96,54 @@ const result = IndexSchema.parse(data); | **mru** | `boolean` | optional | Track Most Recently Used (MRU) list for users | | **clone** | `boolean` | optional | Allow record deep cloning | +--- + +## PartitioningConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **enabled** | `boolean` | ✅ | Enable table partitioning | +| **strategy** | `Enum<'range' \| 'hash' \| 'list'>` | ✅ | Partitioning strategy: range (date ranges), hash (consistent hashing), list (predefined values) | +| **key** | `string` | ✅ | Field name to partition by | +| **interval** | `string` | optional | Partition interval for range strategy (e.g., "1 month", "1 year") | + +--- + +## SoftDeleteConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **enabled** | `boolean` | ✅ | Enable soft delete (trash/recycle bin) | +| **field** | `string` | optional | Field name for soft delete timestamp | +| **cascadeDelete** | `boolean` | optional | Cascade soft delete to related records | + +--- + +## TenancyConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **enabled** | `boolean` | ✅ | Enable multi-tenancy for this object | +| **strategy** | `Enum<'shared' \| 'isolated' \| 'hybrid'>` | ✅ | Tenant isolation strategy: shared (single DB, row-level), isolated (separate DB per tenant), hybrid (mix) | +| **tenantField** | `string` | optional | Field name for tenant identifier | +| **crossTenantAccess** | `boolean` | optional | Allow cross-tenant data access (with explicit permission) | + +--- + +## VersioningConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **enabled** | `boolean` | ✅ | Enable record versioning | +| **strategy** | `Enum<'snapshot' \| 'delta' \| 'event-sourcing'>` | ✅ | Versioning strategy: snapshot (full copy), delta (changes only), event-sourcing (event log) | +| **retentionDays** | `number` | optional | Number of days to retain old versions (undefined = infinite) | +| **versionField** | `string` | optional | Field name for version number/timestamp | + diff --git a/content/docs/references/system/driver-sql.mdx b/content/docs/references/system/driver-sql.mdx new file mode 100644 index 000000000..89c357ad9 --- /dev/null +++ b/content/docs/references/system/driver-sql.mdx @@ -0,0 +1,82 @@ +--- +title: Driver Sql +description: Driver Sql protocol schemas +--- + +# Driver Sql + + +**Source:** `packages/spec/src/system/driver-sql.zod.ts` + + +## TypeScript Usage + +```typescript +import { DataTypeMappingSchema, SQLDialectSchema, SQLDriverConfigSchema, SSLConfigSchema } from '@objectstack/spec/system'; +import type { DataTypeMapping, SQLDialect, SQLDriverConfig, SSLConfig } from '@objectstack/spec/system'; + +// Validate data +const result = DataTypeMappingSchema.parse(data); +``` + +--- + +## DataTypeMapping + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **text** | `string` | ✅ | SQL type for text fields (e.g., VARCHAR, TEXT) | +| **number** | `string` | ✅ | SQL type for number fields (e.g., NUMERIC, DECIMAL, INT) | +| **boolean** | `string` | ✅ | SQL type for boolean fields (e.g., BOOLEAN, BIT) | +| **date** | `string` | ✅ | SQL type for date fields (e.g., DATE) | +| **datetime** | `string` | ✅ | SQL type for datetime fields (e.g., TIMESTAMP, DATETIME) | +| **json** | `string` | optional | SQL type for JSON fields (e.g., JSON, JSONB) | +| **uuid** | `string` | optional | SQL type for UUID fields (e.g., UUID, CHAR(36)) | +| **binary** | `string` | optional | SQL type for binary fields (e.g., BLOB, BYTEA) | + +--- + +## SQLDialect + +### Allowed Values + +* `postgresql` +* `mysql` +* `sqlite` +* `mssql` +* `oracle` +* `mariadb` + +--- + +## SQLDriverConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **name** | `string` | ✅ | Driver instance name | +| **type** | `string` | ✅ | Driver type must be "sql" | +| **capabilities** | `object` | ✅ | Driver capability flags | +| **connectionString** | `string` | optional | Database connection string (driver-specific format) | +| **poolConfig** | `object` | optional | Connection pool configuration | +| **dialect** | `Enum<'postgresql' \| 'mysql' \| 'sqlite' \| 'mssql' \| 'oracle' \| 'mariadb'>` | ✅ | SQL database dialect | +| **dataTypeMapping** | `object` | ✅ | SQL data type mapping configuration | +| **ssl** | `boolean` | optional | Enable SSL/TLS connection | +| **sslConfig** | `object` | optional | SSL/TLS configuration (required when ssl is true) | + +--- + +## SSLConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **rejectUnauthorized** | `boolean` | optional | Reject connections with invalid certificates | +| **ca** | `string` | optional | CA certificate file path or content | +| **cert** | `string` | optional | Client certificate file path or content | +| **key** | `string` | optional | Client private key file path or content | + diff --git a/content/docs/references/system/driver.mdx b/content/docs/references/system/driver.mdx index c6cc834e4..b9ac493f9 100644 --- a/content/docs/references/system/driver.mdx +++ b/content/docs/references/system/driver.mdx @@ -12,8 +12,8 @@ description: Driver protocol schemas ## TypeScript Usage ```typescript -import { DriverCapabilitiesSchema, DriverInterfaceSchema, DriverOptionsSchema } from '@objectstack/spec/system'; -import type { DriverCapabilities, DriverInterface, DriverOptions } from '@objectstack/spec/system'; +import { DriverCapabilitiesSchema, DriverConfigSchema, DriverInterfaceSchema, DriverOptionsSchema, PoolConfigSchema } from '@objectstack/spec/system'; +import type { DriverCapabilities, DriverConfig, DriverInterface, DriverOptions, PoolConfig } from '@objectstack/spec/system'; // Validate data const result = DriverCapabilitiesSchema.parse(data); @@ -27,19 +27,52 @@ const result = DriverCapabilitiesSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **transactions** | `boolean` | ✅ | Supports transactions | -| **queryFilters** | `boolean` | ✅ | Supports WHERE clause filtering | -| **queryAggregations** | `boolean` | ✅ | Supports GROUP BY and aggregation functions | -| **querySorting** | `boolean` | ✅ | Supports ORDER BY sorting | -| **queryPagination** | `boolean` | ✅ | Supports LIMIT/OFFSET pagination | -| **queryWindowFunctions** | `boolean` | ✅ | Supports window functions with OVER clause | -| **querySubqueries** | `boolean` | ✅ | Supports subqueries | -| **joins** | `boolean` | ✅ | Supports SQL joins | -| **fullTextSearch** | `boolean` | ✅ | Supports full-text search | -| **jsonFields** | `boolean` | ✅ | Supports JSON field types | -| **arrayFields** | `boolean` | ✅ | Supports array field types | +| **create** | `boolean` | optional | Supports CREATE operations | +| **read** | `boolean` | optional | Supports READ operations | +| **update** | `boolean` | optional | Supports UPDATE operations | +| **delete** | `boolean` | optional | Supports DELETE operations | +| **bulkCreate** | `boolean` | optional | Supports bulk CREATE operations | +| **bulkUpdate** | `boolean` | optional | Supports bulk UPDATE operations | +| **bulkDelete** | `boolean` | optional | Supports bulk DELETE operations | +| **transactions** | `boolean` | optional | Supports ACID transactions | +| **savepoints** | `boolean` | optional | Supports transaction savepoints | +| **isolationLevels** | `Enum<'read-uncommitted' \| 'read-committed' \| 'repeatable-read' \| 'serializable'>[]` | optional | Supported transaction isolation levels | +| **queryFilters** | `boolean` | optional | Supports WHERE clause filtering | +| **queryAggregations** | `boolean` | optional | Supports GROUP BY and aggregation functions | +| **querySorting** | `boolean` | optional | Supports ORDER BY sorting | +| **queryPagination** | `boolean` | optional | Supports LIMIT/OFFSET pagination | +| **queryWindowFunctions** | `boolean` | optional | Supports window functions with OVER clause | +| **querySubqueries** | `boolean` | optional | Supports subqueries | +| **queryCTE** | `boolean` | optional | Supports Common Table Expressions (WITH clause) | +| **joins** | `boolean` | optional | Supports SQL joins | +| **fullTextSearch** | `boolean` | optional | Supports full-text search | +| **jsonQuery** | `boolean` | optional | Supports JSON field querying | +| **geospatialQuery** | `boolean` | optional | Supports geospatial queries | +| **streaming** | `boolean` | optional | Supports result streaming (cursors/iterators) | +| **jsonFields** | `boolean` | optional | Supports JSON field types | +| **arrayFields** | `boolean` | optional | Supports array field types | | **vectorSearch** | `boolean` | optional | Supports vector embeddings and similarity search | -| **geoSpatial** | `boolean` | optional | Supports geospatial queries | +| **geoSpatial** | `boolean` | optional | Supports geospatial queries (deprecated: use geospatialQuery) | +| **schemaSync** | `boolean` | optional | Supports automatic schema synchronization | +| **migrations** | `boolean` | optional | Supports database migrations | +| **indexes** | `boolean` | optional | Supports index creation and management | +| **connectionPooling** | `boolean` | optional | Supports connection pooling | +| **preparedStatements** | `boolean` | optional | Supports prepared statements (SQL injection prevention) | +| **queryCache** | `boolean` | optional | Supports query result caching | + +--- + +## DriverConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **name** | `string` | ✅ | Driver instance name | +| **type** | `Enum<'sql' \| 'nosql' \| 'cache' \| 'search' \| 'graph' \| 'timeseries'>` | ✅ | Driver type category | +| **capabilities** | `object` | ✅ | Driver capability flags | +| **connectionString** | `string` | optional | Database connection string (driver-specific format) | +| **poolConfig** | `object` | optional | Connection pool configuration | --- @@ -67,3 +100,16 @@ const result = DriverCapabilitiesSchema.parse(data); | **traceContext** | `Record` | optional | OpenTelemetry context or request ID | | **tenantId** | `string` | optional | Tenant Isolation identifier | +--- + +## PoolConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **min** | `number` | optional | Minimum number of connections in pool | +| **max** | `number` | optional | Maximum number of connections in pool | +| **idleTimeoutMillis** | `number` | optional | Time in ms before idle connection is closed | +| **connectionTimeoutMillis** | `number` | optional | Time in ms to wait for available connection | + diff --git a/content/docs/references/system/index.mdx b/content/docs/references/system/index.mdx index 77b5e92c7..8e001daed 100644 --- a/content/docs/references/system/index.mdx +++ b/content/docs/references/system/index.mdx @@ -16,6 +16,7 @@ This section contains all protocol schemas for the system layer of ObjectStack. + diff --git a/content/docs/references/system/meta.json b/content/docs/references/system/meta.json index e95f6aa63..3c47f9299 100644 --- a/content/docs/references/system/meta.json +++ b/content/docs/references/system/meta.json @@ -9,6 +9,7 @@ "data-engine", "datasource", "driver", + "driver-sql", "encryption", "events", "feature", diff --git a/packages/spec/json-schema/data/CDCConfig.json b/packages/spec/json-schema/data/CDCConfig.json new file mode 100644 index 000000000..84cc0f788 --- /dev/null +++ b/packages/spec/json-schema/data/CDCConfig.json @@ -0,0 +1,37 @@ +{ + "$ref": "#/definitions/CDCConfig", + "definitions": { + "CDCConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable Change Data Capture" + }, + "events": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "insert", + "update", + "delete" + ] + }, + "description": "Event types to capture" + }, + "destination": { + "type": "string", + "description": "Destination endpoint (e.g., \"kafka://topic\", \"webhook://url\")" + } + }, + "required": [ + "enabled", + "events", + "destination" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/data/ComputedFieldCache.json b/packages/spec/json-schema/data/ComputedFieldCache.json new file mode 100644 index 000000000..55a504ea6 --- /dev/null +++ b/packages/spec/json-schema/data/ComputedFieldCache.json @@ -0,0 +1,33 @@ +{ + "$ref": "#/definitions/ComputedFieldCache", + "definitions": { + "ComputedFieldCache": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable caching for computed field results" + }, + "ttl": { + "type": "number", + "minimum": 0, + "description": "Cache TTL in seconds (0 = no expiration)" + }, + "invalidateOn": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field paths that invalidate cache (e.g., [\"inventory.quantity\", \"pricing.base_price\"])" + } + }, + "required": [ + "enabled", + "ttl", + "invalidateOn" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/data/DataQualityRules.json b/packages/spec/json-schema/data/DataQualityRules.json new file mode 100644 index 000000000..14b892d50 --- /dev/null +++ b/packages/spec/json-schema/data/DataQualityRules.json @@ -0,0 +1,45 @@ +{ + "$ref": "#/definitions/DataQualityRules", + "definitions": { + "DataQualityRules": { + "type": "object", + "properties": { + "uniqueness": { + "type": "boolean", + "default": false, + "description": "Enforce unique values across all records" + }, + "completeness": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 0, + "description": "Minimum ratio of non-null values (0-1, default: 0 = no requirement)" + }, + "accuracy": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Reference data source for validation (e.g., \"api.verify.com\", \"master_data\")" + }, + "threshold": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Minimum accuracy threshold (0-1, e.g., 0.95 = 95% match required)" + } + }, + "required": [ + "source", + "threshold" + ], + "additionalProperties": false, + "description": "Accuracy validation configuration" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/data/Field.json b/packages/spec/json-schema/data/Field.json index fbb00ca3a..7dd8aa0c1 100644 --- a/packages/spec/json-schema/data/Field.json +++ b/packages/spec/json-schema/data/Field.json @@ -605,6 +605,226 @@ "additionalProperties": false, "description": "Configuration for file and attachment field types" }, + "encryptionConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "algorithm": { + "type": "string", + "enum": [ + "aes-256-gcm", + "aes-256-cbc", + "chacha20-poly1305" + ], + "default": "aes-256-gcm" + }, + "keyManagement": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "enum": [ + "local", + "aws-kms", + "azure-key-vault", + "gcp-kms", + "hashicorp-vault" + ] + }, + "keyId": { + "type": "string" + }, + "rotationPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "frequencyDays": { + "type": "number", + "minimum": 1, + "default": 90 + }, + "retainOldVersions": { + "type": "number", + "default": 3 + }, + "autoRotate": { + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + } + }, + "required": [ + "provider" + ], + "additionalProperties": false + }, + "scope": { + "type": "string", + "enum": [ + "field", + "record", + "table", + "database" + ] + }, + "deterministicEncryption": { + "type": "boolean", + "default": false, + "description": "Allows equality queries on encrypted data" + }, + "searchableEncryption": { + "type": "boolean", + "default": false, + "description": "Allows search on encrypted data" + } + }, + "required": [ + "keyManagement", + "scope" + ], + "additionalProperties": false, + "description": "Field-level encryption configuration for sensitive data (GDPR/HIPAA/PCI-DSS)" + }, + "maskingRule": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "strategy": { + "type": "string", + "enum": [ + "redact", + "partial", + "hash", + "tokenize", + "randomize", + "nullify", + "substitute" + ] + }, + "pattern": { + "type": "string", + "description": "Regex pattern for partial masking" + }, + "preserveFormat": { + "type": "boolean", + "default": true + }, + "preserveLength": { + "type": "boolean", + "default": true + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Roles that see masked data" + }, + "exemptRoles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Roles that see unmasked data" + } + }, + "required": [ + "field", + "strategy" + ], + "additionalProperties": false, + "description": "Data masking rules for PII protection" + }, + "auditTrail": { + "type": "boolean", + "default": false, + "description": "Enable detailed audit trail for this field (tracks all changes with user and timestamp)" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field names that this field depends on (for formulas, visibility rules, etc.)" + }, + "cached": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable caching for computed field results" + }, + "ttl": { + "type": "number", + "minimum": 0, + "description": "Cache TTL in seconds (0 = no expiration)" + }, + "invalidateOn": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field paths that invalidate cache (e.g., [\"inventory.quantity\", \"pricing.base_price\"])" + } + }, + "required": [ + "enabled", + "ttl", + "invalidateOn" + ], + "additionalProperties": false, + "description": "Caching configuration for computed/formula fields" + }, + "dataQuality": { + "type": "object", + "properties": { + "uniqueness": { + "type": "boolean", + "default": false, + "description": "Enforce unique values across all records" + }, + "completeness": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 0, + "description": "Minimum ratio of non-null values (0-1, default: 0 = no requirement)" + }, + "accuracy": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Reference data source for validation (e.g., \"api.verify.com\", \"master_data\")" + }, + "threshold": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Minimum accuracy threshold (0-1, e.g., 0.95 = 95% match required)" + } + }, + "required": [ + "source", + "threshold" + ], + "additionalProperties": false, + "description": "Accuracy validation configuration" + } + }, + "additionalProperties": false, + "description": "Data quality validation and monitoring rules" + }, "hidden": { "type": "boolean", "default": false, @@ -618,7 +838,7 @@ "encryption": { "type": "boolean", "default": false, - "description": "Encrypt at rest" + "description": "Deprecated: Use encryptionConfig for enhanced encryption features. Simple flag for backward compatibility." }, "index": { "type": "boolean", diff --git a/packages/spec/json-schema/data/Index.json b/packages/spec/json-schema/data/Index.json index ebccfd7fd..c4c25f1de 100644 --- a/packages/spec/json-schema/data/Index.json +++ b/packages/spec/json-schema/data/Index.json @@ -6,7 +6,7 @@ "properties": { "name": { "type": "string", - "description": "Index name" + "description": "Index name (auto-generated if not provided)" }, "fields": { "type": "array", @@ -15,19 +15,26 @@ }, "description": "Fields included in the index" }, - "unique": { - "type": "boolean", - "description": "Whether the index is unique" - }, "type": { "type": "string", "enum": [ "btree", "hash", "gin", - "gist" + "gist", + "fulltext" ], - "description": "Index type (default: btree)" + "default": "btree", + "description": "Index algorithm type" + }, + "unique": { + "type": "boolean", + "default": false, + "description": "Whether the index enforces uniqueness" + }, + "partial": { + "type": "string", + "description": "Partial index condition (SQL WHERE clause for conditional indexes)" } }, "required": [ diff --git a/packages/spec/json-schema/data/Object.json b/packages/spec/json-schema/data/Object.json index fbc645dd2..e4a43d83c 100644 --- a/packages/spec/json-schema/data/Object.json +++ b/packages/spec/json-schema/data/Object.json @@ -662,6 +662,226 @@ "additionalProperties": false, "description": "Configuration for file and attachment field types" }, + "encryptionConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "algorithm": { + "type": "string", + "enum": [ + "aes-256-gcm", + "aes-256-cbc", + "chacha20-poly1305" + ], + "default": "aes-256-gcm" + }, + "keyManagement": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "enum": [ + "local", + "aws-kms", + "azure-key-vault", + "gcp-kms", + "hashicorp-vault" + ] + }, + "keyId": { + "type": "string" + }, + "rotationPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "frequencyDays": { + "type": "number", + "minimum": 1, + "default": 90 + }, + "retainOldVersions": { + "type": "number", + "default": 3 + }, + "autoRotate": { + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + } + }, + "required": [ + "provider" + ], + "additionalProperties": false + }, + "scope": { + "type": "string", + "enum": [ + "field", + "record", + "table", + "database" + ] + }, + "deterministicEncryption": { + "type": "boolean", + "default": false, + "description": "Allows equality queries on encrypted data" + }, + "searchableEncryption": { + "type": "boolean", + "default": false, + "description": "Allows search on encrypted data" + } + }, + "required": [ + "keyManagement", + "scope" + ], + "additionalProperties": false, + "description": "Field-level encryption configuration for sensitive data (GDPR/HIPAA/PCI-DSS)" + }, + "maskingRule": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "strategy": { + "type": "string", + "enum": [ + "redact", + "partial", + "hash", + "tokenize", + "randomize", + "nullify", + "substitute" + ] + }, + "pattern": { + "type": "string", + "description": "Regex pattern for partial masking" + }, + "preserveFormat": { + "type": "boolean", + "default": true + }, + "preserveLength": { + "type": "boolean", + "default": true + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Roles that see masked data" + }, + "exemptRoles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Roles that see unmasked data" + } + }, + "required": [ + "field", + "strategy" + ], + "additionalProperties": false, + "description": "Data masking rules for PII protection" + }, + "auditTrail": { + "type": "boolean", + "default": false, + "description": "Enable detailed audit trail for this field (tracks all changes with user and timestamp)" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field names that this field depends on (for formulas, visibility rules, etc.)" + }, + "cached": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable caching for computed field results" + }, + "ttl": { + "type": "number", + "minimum": 0, + "description": "Cache TTL in seconds (0 = no expiration)" + }, + "invalidateOn": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field paths that invalidate cache (e.g., [\"inventory.quantity\", \"pricing.base_price\"])" + } + }, + "required": [ + "enabled", + "ttl", + "invalidateOn" + ], + "additionalProperties": false, + "description": "Caching configuration for computed/formula fields" + }, + "dataQuality": { + "type": "object", + "properties": { + "uniqueness": { + "type": "boolean", + "default": false, + "description": "Enforce unique values across all records" + }, + "completeness": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 0, + "description": "Minimum ratio of non-null values (0-1, default: 0 = no requirement)" + }, + "accuracy": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Reference data source for validation (e.g., \"api.verify.com\", \"master_data\")" + }, + "threshold": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Minimum accuracy threshold (0-1, e.g., 0.95 = 95% match required)" + } + }, + "required": [ + "source", + "threshold" + ], + "additionalProperties": false, + "description": "Accuracy validation configuration" + } + }, + "additionalProperties": false, + "description": "Data quality validation and monitoring rules" + }, "hidden": { "type": "boolean", "default": false, @@ -675,7 +895,7 @@ "encryption": { "type": "boolean", "default": false, - "description": "Encrypt at rest" + "description": "Deprecated: Use encryptionConfig for enhanced encryption features. Simple flag for backward compatibility." }, "index": { "type": "boolean", @@ -702,7 +922,7 @@ "properties": { "name": { "type": "string", - "description": "Index name" + "description": "Index name (auto-generated if not provided)" }, "fields": { "type": "array", @@ -711,19 +931,26 @@ }, "description": "Fields included in the index" }, - "unique": { - "type": "boolean", - "description": "Whether the index is unique" - }, "type": { "type": "string", "enum": [ "btree", "hash", "gin", - "gist" + "gist", + "fulltext" ], - "description": "Index type (default: btree)" + "default": "btree", + "description": "Index algorithm type" + }, + "unique": { + "type": "boolean", + "default": false, + "description": "Whether the index enforces uniqueness" + }, + "partial": { + "type": "string", + "description": "Partial index condition (SQL WHERE clause for conditional indexes)" } }, "required": [ @@ -733,6 +960,163 @@ }, "description": "Database performance indexes" }, + "tenancy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable multi-tenancy for this object" + }, + "strategy": { + "type": "string", + "enum": [ + "shared", + "isolated", + "hybrid" + ], + "description": "Tenant isolation strategy: shared (single DB, row-level), isolated (separate DB per tenant), hybrid (mix)" + }, + "tenantField": { + "type": "string", + "default": "tenant_id", + "description": "Field name for tenant identifier" + }, + "crossTenantAccess": { + "type": "boolean", + "default": false, + "description": "Allow cross-tenant data access (with explicit permission)" + } + }, + "required": [ + "enabled", + "strategy" + ], + "additionalProperties": false, + "description": "Multi-tenancy configuration for SaaS applications" + }, + "softDelete": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable soft delete (trash/recycle bin)" + }, + "field": { + "type": "string", + "default": "deleted_at", + "description": "Field name for soft delete timestamp" + }, + "cascadeDelete": { + "type": "boolean", + "default": false, + "description": "Cascade soft delete to related records" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false, + "description": "Soft delete (trash/recycle bin) configuration" + }, + "versioning": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable record versioning" + }, + "strategy": { + "type": "string", + "enum": [ + "snapshot", + "delta", + "event-sourcing" + ], + "description": "Versioning strategy: snapshot (full copy), delta (changes only), event-sourcing (event log)" + }, + "retentionDays": { + "type": "number", + "minimum": 1, + "description": "Number of days to retain old versions (undefined = infinite)" + }, + "versionField": { + "type": "string", + "default": "version", + "description": "Field name for version number/timestamp" + } + }, + "required": [ + "enabled", + "strategy" + ], + "additionalProperties": false, + "description": "Record versioning and history tracking configuration" + }, + "partitioning": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable table partitioning" + }, + "strategy": { + "type": "string", + "enum": [ + "range", + "hash", + "list" + ], + "description": "Partitioning strategy: range (date ranges), hash (consistent hashing), list (predefined values)" + }, + "key": { + "type": "string", + "description": "Field name to partition by" + }, + "interval": { + "type": "string", + "description": "Partition interval for range strategy (e.g., \"1 month\", \"1 year\")" + } + }, + "required": [ + "enabled", + "strategy", + "key" + ], + "additionalProperties": false, + "description": "Table partitioning configuration for performance" + }, + "cdc": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable Change Data Capture" + }, + "events": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "insert", + "update", + "delete" + ] + }, + "description": "Event types to capture" + }, + "destination": { + "type": "string", + "description": "Destination endpoint (e.g., \"kafka://topic\", \"webhook://url\")" + } + }, + "required": [ + "enabled", + "events", + "destination" + ], + "additionalProperties": false, + "description": "Change Data Capture (CDC) configuration for real-time data streaming" + }, "validations": { "type": "array", "items": { diff --git a/packages/spec/json-schema/data/PartitioningConfig.json b/packages/spec/json-schema/data/PartitioningConfig.json new file mode 100644 index 000000000..e3eca199d --- /dev/null +++ b/packages/spec/json-schema/data/PartitioningConfig.json @@ -0,0 +1,38 @@ +{ + "$ref": "#/definitions/PartitioningConfig", + "definitions": { + "PartitioningConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable table partitioning" + }, + "strategy": { + "type": "string", + "enum": [ + "range", + "hash", + "list" + ], + "description": "Partitioning strategy: range (date ranges), hash (consistent hashing), list (predefined values)" + }, + "key": { + "type": "string", + "description": "Field name to partition by" + }, + "interval": { + "type": "string", + "description": "Partition interval for range strategy (e.g., \"1 month\", \"1 year\")" + } + }, + "required": [ + "enabled", + "strategy", + "key" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/data/SoftDeleteConfig.json b/packages/spec/json-schema/data/SoftDeleteConfig.json new file mode 100644 index 000000000..bfb206cd5 --- /dev/null +++ b/packages/spec/json-schema/data/SoftDeleteConfig.json @@ -0,0 +1,29 @@ +{ + "$ref": "#/definitions/SoftDeleteConfig", + "definitions": { + "SoftDeleteConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable soft delete (trash/recycle bin)" + }, + "field": { + "type": "string", + "default": "deleted_at", + "description": "Field name for soft delete timestamp" + }, + "cascadeDelete": { + "type": "boolean", + "default": false, + "description": "Cascade soft delete to related records" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/data/TenancyConfig.json b/packages/spec/json-schema/data/TenancyConfig.json new file mode 100644 index 000000000..a49d1836b --- /dev/null +++ b/packages/spec/json-schema/data/TenancyConfig.json @@ -0,0 +1,39 @@ +{ + "$ref": "#/definitions/TenancyConfig", + "definitions": { + "TenancyConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable multi-tenancy for this object" + }, + "strategy": { + "type": "string", + "enum": [ + "shared", + "isolated", + "hybrid" + ], + "description": "Tenant isolation strategy: shared (single DB, row-level), isolated (separate DB per tenant), hybrid (mix)" + }, + "tenantField": { + "type": "string", + "default": "tenant_id", + "description": "Field name for tenant identifier" + }, + "crossTenantAccess": { + "type": "boolean", + "default": false, + "description": "Allow cross-tenant data access (with explicit permission)" + } + }, + "required": [ + "enabled", + "strategy" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/data/VersioningConfig.json b/packages/spec/json-schema/data/VersioningConfig.json new file mode 100644 index 000000000..b9b9cbd26 --- /dev/null +++ b/packages/spec/json-schema/data/VersioningConfig.json @@ -0,0 +1,39 @@ +{ + "$ref": "#/definitions/VersioningConfig", + "definitions": { + "VersioningConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable record versioning" + }, + "strategy": { + "type": "string", + "enum": [ + "snapshot", + "delta", + "event-sourcing" + ], + "description": "Versioning strategy: snapshot (full copy), delta (changes only), event-sourcing (event log)" + }, + "retentionDays": { + "type": "number", + "minimum": 1, + "description": "Number of days to retain old versions (undefined = infinite)" + }, + "versionField": { + "type": "string", + "default": "version", + "description": "Field name for version number/timestamp" + } + }, + "required": [ + "enabled", + "strategy" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/DataTypeMapping.json b/packages/spec/json-schema/system/DataTypeMapping.json new file mode 100644 index 000000000..20de4738c --- /dev/null +++ b/packages/spec/json-schema/system/DataTypeMapping.json @@ -0,0 +1,51 @@ +{ + "$ref": "#/definitions/DataTypeMapping", + "definitions": { + "DataTypeMapping": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "SQL type for text fields (e.g., VARCHAR, TEXT)" + }, + "number": { + "type": "string", + "description": "SQL type for number fields (e.g., NUMERIC, DECIMAL, INT)" + }, + "boolean": { + "type": "string", + "description": "SQL type for boolean fields (e.g., BOOLEAN, BIT)" + }, + "date": { + "type": "string", + "description": "SQL type for date fields (e.g., DATE)" + }, + "datetime": { + "type": "string", + "description": "SQL type for datetime fields (e.g., TIMESTAMP, DATETIME)" + }, + "json": { + "type": "string", + "description": "SQL type for JSON fields (e.g., JSON, JSONB)" + }, + "uuid": { + "type": "string", + "description": "SQL type for UUID fields (e.g., UUID, CHAR(36))" + }, + "binary": { + "type": "string", + "description": "SQL type for binary fields (e.g., BLOB, BYTEA)" + } + }, + "required": [ + "text", + "number", + "boolean", + "date", + "datetime" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/DriverCapabilities.json b/packages/spec/json-schema/system/DriverCapabilities.json index 45ba7ca27..70b79c5ee 100644 --- a/packages/spec/json-schema/system/DriverCapabilities.json +++ b/packages/spec/json-schema/system/DriverCapabilities.json @@ -4,48 +4,132 @@ "DriverCapabilities": { "type": "object", "properties": { + "create": { + "type": "boolean", + "default": true, + "description": "Supports CREATE operations" + }, + "read": { + "type": "boolean", + "default": true, + "description": "Supports READ operations" + }, + "update": { + "type": "boolean", + "default": true, + "description": "Supports UPDATE operations" + }, + "delete": { + "type": "boolean", + "default": true, + "description": "Supports DELETE operations" + }, + "bulkCreate": { + "type": "boolean", + "default": false, + "description": "Supports bulk CREATE operations" + }, + "bulkUpdate": { + "type": "boolean", + "default": false, + "description": "Supports bulk UPDATE operations" + }, + "bulkDelete": { + "type": "boolean", + "default": false, + "description": "Supports bulk DELETE operations" + }, "transactions": { "type": "boolean", - "description": "Supports transactions" + "default": false, + "description": "Supports ACID transactions" + }, + "savepoints": { + "type": "boolean", + "default": false, + "description": "Supports transaction savepoints" + }, + "isolationLevels": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "read-uncommitted", + "read-committed", + "repeatable-read", + "serializable" + ] + }, + "description": "Supported transaction isolation levels" }, "queryFilters": { "type": "boolean", + "default": true, "description": "Supports WHERE clause filtering" }, "queryAggregations": { "type": "boolean", + "default": false, "description": "Supports GROUP BY and aggregation functions" }, "querySorting": { "type": "boolean", + "default": true, "description": "Supports ORDER BY sorting" }, "queryPagination": { "type": "boolean", + "default": true, "description": "Supports LIMIT/OFFSET pagination" }, "queryWindowFunctions": { "type": "boolean", + "default": false, "description": "Supports window functions with OVER clause" }, "querySubqueries": { "type": "boolean", + "default": false, "description": "Supports subqueries" }, + "queryCTE": { + "type": "boolean", + "default": false, + "description": "Supports Common Table Expressions (WITH clause)" + }, "joins": { "type": "boolean", + "default": false, "description": "Supports SQL joins" }, "fullTextSearch": { "type": "boolean", + "default": false, "description": "Supports full-text search" }, + "jsonQuery": { + "type": "boolean", + "default": false, + "description": "Supports JSON field querying" + }, + "geospatialQuery": { + "type": "boolean", + "default": false, + "description": "Supports geospatial queries" + }, + "streaming": { + "type": "boolean", + "default": false, + "description": "Supports result streaming (cursors/iterators)" + }, "jsonFields": { "type": "boolean", + "default": false, "description": "Supports JSON field types" }, "arrayFields": { "type": "boolean", + "default": false, "description": "Supports array field types" }, "vectorSearch": { @@ -56,22 +140,39 @@ "geoSpatial": { "type": "boolean", "default": false, - "description": "Supports geospatial queries" + "description": "Supports geospatial queries (deprecated: use geospatialQuery)" + }, + "schemaSync": { + "type": "boolean", + "default": false, + "description": "Supports automatic schema synchronization" + }, + "migrations": { + "type": "boolean", + "default": false, + "description": "Supports database migrations" + }, + "indexes": { + "type": "boolean", + "default": false, + "description": "Supports index creation and management" + }, + "connectionPooling": { + "type": "boolean", + "default": false, + "description": "Supports connection pooling" + }, + "preparedStatements": { + "type": "boolean", + "default": false, + "description": "Supports prepared statements (SQL injection prevention)" + }, + "queryCache": { + "type": "boolean", + "default": false, + "description": "Supports query result caching" } }, - "required": [ - "transactions", - "queryFilters", - "queryAggregations", - "querySorting", - "queryPagination", - "queryWindowFunctions", - "querySubqueries", - "joins", - "fullTextSearch", - "jsonFields", - "arrayFields" - ], "additionalProperties": false } }, diff --git a/packages/spec/json-schema/system/DriverConfig.json b/packages/spec/json-schema/system/DriverConfig.json new file mode 100644 index 000000000..1d79d306e --- /dev/null +++ b/packages/spec/json-schema/system/DriverConfig.json @@ -0,0 +1,243 @@ +{ + "$ref": "#/definitions/DriverConfig", + "definitions": { + "DriverConfig": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Driver instance name" + }, + "type": { + "type": "string", + "enum": [ + "sql", + "nosql", + "cache", + "search", + "graph", + "timeseries" + ], + "description": "Driver type category" + }, + "capabilities": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "default": true, + "description": "Supports CREATE operations" + }, + "read": { + "type": "boolean", + "default": true, + "description": "Supports READ operations" + }, + "update": { + "type": "boolean", + "default": true, + "description": "Supports UPDATE operations" + }, + "delete": { + "type": "boolean", + "default": true, + "description": "Supports DELETE operations" + }, + "bulkCreate": { + "type": "boolean", + "default": false, + "description": "Supports bulk CREATE operations" + }, + "bulkUpdate": { + "type": "boolean", + "default": false, + "description": "Supports bulk UPDATE operations" + }, + "bulkDelete": { + "type": "boolean", + "default": false, + "description": "Supports bulk DELETE operations" + }, + "transactions": { + "type": "boolean", + "default": false, + "description": "Supports ACID transactions" + }, + "savepoints": { + "type": "boolean", + "default": false, + "description": "Supports transaction savepoints" + }, + "isolationLevels": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "read-uncommitted", + "read-committed", + "repeatable-read", + "serializable" + ] + }, + "description": "Supported transaction isolation levels" + }, + "queryFilters": { + "type": "boolean", + "default": true, + "description": "Supports WHERE clause filtering" + }, + "queryAggregations": { + "type": "boolean", + "default": false, + "description": "Supports GROUP BY and aggregation functions" + }, + "querySorting": { + "type": "boolean", + "default": true, + "description": "Supports ORDER BY sorting" + }, + "queryPagination": { + "type": "boolean", + "default": true, + "description": "Supports LIMIT/OFFSET pagination" + }, + "queryWindowFunctions": { + "type": "boolean", + "default": false, + "description": "Supports window functions with OVER clause" + }, + "querySubqueries": { + "type": "boolean", + "default": false, + "description": "Supports subqueries" + }, + "queryCTE": { + "type": "boolean", + "default": false, + "description": "Supports Common Table Expressions (WITH clause)" + }, + "joins": { + "type": "boolean", + "default": false, + "description": "Supports SQL joins" + }, + "fullTextSearch": { + "type": "boolean", + "default": false, + "description": "Supports full-text search" + }, + "jsonQuery": { + "type": "boolean", + "default": false, + "description": "Supports JSON field querying" + }, + "geospatialQuery": { + "type": "boolean", + "default": false, + "description": "Supports geospatial queries" + }, + "streaming": { + "type": "boolean", + "default": false, + "description": "Supports result streaming (cursors/iterators)" + }, + "jsonFields": { + "type": "boolean", + "default": false, + "description": "Supports JSON field types" + }, + "arrayFields": { + "type": "boolean", + "default": false, + "description": "Supports array field types" + }, + "vectorSearch": { + "type": "boolean", + "default": false, + "description": "Supports vector embeddings and similarity search" + }, + "geoSpatial": { + "type": "boolean", + "default": false, + "description": "Supports geospatial queries (deprecated: use geospatialQuery)" + }, + "schemaSync": { + "type": "boolean", + "default": false, + "description": "Supports automatic schema synchronization" + }, + "migrations": { + "type": "boolean", + "default": false, + "description": "Supports database migrations" + }, + "indexes": { + "type": "boolean", + "default": false, + "description": "Supports index creation and management" + }, + "connectionPooling": { + "type": "boolean", + "default": false, + "description": "Supports connection pooling" + }, + "preparedStatements": { + "type": "boolean", + "default": false, + "description": "Supports prepared statements (SQL injection prevention)" + }, + "queryCache": { + "type": "boolean", + "default": false, + "description": "Supports query result caching" + } + }, + "additionalProperties": false, + "description": "Driver capability flags" + }, + "connectionString": { + "type": "string", + "description": "Database connection string (driver-specific format)" + }, + "poolConfig": { + "type": "object", + "properties": { + "min": { + "type": "number", + "minimum": 0, + "default": 2, + "description": "Minimum number of connections in pool" + }, + "max": { + "type": "number", + "minimum": 1, + "default": 10, + "description": "Maximum number of connections in pool" + }, + "idleTimeoutMillis": { + "type": "number", + "minimum": 0, + "default": 30000, + "description": "Time in ms before idle connection is closed" + }, + "connectionTimeoutMillis": { + "type": "number", + "minimum": 0, + "default": 5000, + "description": "Time in ms to wait for available connection" + } + }, + "additionalProperties": false, + "description": "Connection pool configuration" + } + }, + "required": [ + "name", + "type", + "capabilities" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/DriverInterface.json b/packages/spec/json-schema/system/DriverInterface.json index 62fad4070..8ae878829 100644 --- a/packages/spec/json-schema/system/DriverInterface.json +++ b/packages/spec/json-schema/system/DriverInterface.json @@ -15,48 +15,132 @@ "supports": { "type": "object", "properties": { + "create": { + "type": "boolean", + "default": true, + "description": "Supports CREATE operations" + }, + "read": { + "type": "boolean", + "default": true, + "description": "Supports READ operations" + }, + "update": { + "type": "boolean", + "default": true, + "description": "Supports UPDATE operations" + }, + "delete": { + "type": "boolean", + "default": true, + "description": "Supports DELETE operations" + }, + "bulkCreate": { + "type": "boolean", + "default": false, + "description": "Supports bulk CREATE operations" + }, + "bulkUpdate": { + "type": "boolean", + "default": false, + "description": "Supports bulk UPDATE operations" + }, + "bulkDelete": { + "type": "boolean", + "default": false, + "description": "Supports bulk DELETE operations" + }, "transactions": { "type": "boolean", - "description": "Supports transactions" + "default": false, + "description": "Supports ACID transactions" + }, + "savepoints": { + "type": "boolean", + "default": false, + "description": "Supports transaction savepoints" + }, + "isolationLevels": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "read-uncommitted", + "read-committed", + "repeatable-read", + "serializable" + ] + }, + "description": "Supported transaction isolation levels" }, "queryFilters": { "type": "boolean", + "default": true, "description": "Supports WHERE clause filtering" }, "queryAggregations": { "type": "boolean", + "default": false, "description": "Supports GROUP BY and aggregation functions" }, "querySorting": { "type": "boolean", + "default": true, "description": "Supports ORDER BY sorting" }, "queryPagination": { "type": "boolean", + "default": true, "description": "Supports LIMIT/OFFSET pagination" }, "queryWindowFunctions": { "type": "boolean", + "default": false, "description": "Supports window functions with OVER clause" }, "querySubqueries": { "type": "boolean", + "default": false, "description": "Supports subqueries" }, + "queryCTE": { + "type": "boolean", + "default": false, + "description": "Supports Common Table Expressions (WITH clause)" + }, "joins": { "type": "boolean", + "default": false, "description": "Supports SQL joins" }, "fullTextSearch": { "type": "boolean", + "default": false, "description": "Supports full-text search" }, + "jsonQuery": { + "type": "boolean", + "default": false, + "description": "Supports JSON field querying" + }, + "geospatialQuery": { + "type": "boolean", + "default": false, + "description": "Supports geospatial queries" + }, + "streaming": { + "type": "boolean", + "default": false, + "description": "Supports result streaming (cursors/iterators)" + }, "jsonFields": { "type": "boolean", + "default": false, "description": "Supports JSON field types" }, "arrayFields": { "type": "boolean", + "default": false, "description": "Supports array field types" }, "vectorSearch": { @@ -67,22 +151,39 @@ "geoSpatial": { "type": "boolean", "default": false, - "description": "Supports geospatial queries" + "description": "Supports geospatial queries (deprecated: use geospatialQuery)" + }, + "schemaSync": { + "type": "boolean", + "default": false, + "description": "Supports automatic schema synchronization" + }, + "migrations": { + "type": "boolean", + "default": false, + "description": "Supports database migrations" + }, + "indexes": { + "type": "boolean", + "default": false, + "description": "Supports index creation and management" + }, + "connectionPooling": { + "type": "boolean", + "default": false, + "description": "Supports connection pooling" + }, + "preparedStatements": { + "type": "boolean", + "default": false, + "description": "Supports prepared statements (SQL injection prevention)" + }, + "queryCache": { + "type": "boolean", + "default": false, + "description": "Supports query result caching" } }, - "required": [ - "transactions", - "queryFilters", - "queryAggregations", - "querySorting", - "queryPagination", - "queryWindowFunctions", - "querySubqueries", - "joins", - "fullTextSearch", - "jsonFields", - "arrayFields" - ], "additionalProperties": false } }, diff --git a/packages/spec/json-schema/system/PoolConfig.json b/packages/spec/json-schema/system/PoolConfig.json new file mode 100644 index 000000000..9416b7f6f --- /dev/null +++ b/packages/spec/json-schema/system/PoolConfig.json @@ -0,0 +1,36 @@ +{ + "$ref": "#/definitions/PoolConfig", + "definitions": { + "PoolConfig": { + "type": "object", + "properties": { + "min": { + "type": "number", + "minimum": 0, + "default": 2, + "description": "Minimum number of connections in pool" + }, + "max": { + "type": "number", + "minimum": 1, + "default": 10, + "description": "Maximum number of connections in pool" + }, + "idleTimeoutMillis": { + "type": "number", + "minimum": 0, + "default": 30000, + "description": "Time in ms before idle connection is closed" + }, + "connectionTimeoutMillis": { + "type": "number", + "minimum": 0, + "default": 5000, + "description": "Time in ms to wait for available connection" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/SQLDialect.json b/packages/spec/json-schema/system/SQLDialect.json new file mode 100644 index 000000000..a30665b4c --- /dev/null +++ b/packages/spec/json-schema/system/SQLDialect.json @@ -0,0 +1,17 @@ +{ + "$ref": "#/definitions/SQLDialect", + "definitions": { + "SQLDialect": { + "type": "string", + "enum": [ + "postgresql", + "mysql", + "sqlite", + "mssql", + "oracle", + "mariadb" + ] + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/SQLDriverConfig.json b/packages/spec/json-schema/system/SQLDriverConfig.json new file mode 100644 index 000000000..ff0d3c7c7 --- /dev/null +++ b/packages/spec/json-schema/system/SQLDriverConfig.json @@ -0,0 +1,325 @@ +{ + "$ref": "#/definitions/SQLDriverConfig", + "definitions": { + "SQLDriverConfig": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Driver instance name" + }, + "type": { + "type": "string", + "const": "sql", + "description": "Driver type must be \"sql\"" + }, + "capabilities": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "default": true, + "description": "Supports CREATE operations" + }, + "read": { + "type": "boolean", + "default": true, + "description": "Supports READ operations" + }, + "update": { + "type": "boolean", + "default": true, + "description": "Supports UPDATE operations" + }, + "delete": { + "type": "boolean", + "default": true, + "description": "Supports DELETE operations" + }, + "bulkCreate": { + "type": "boolean", + "default": false, + "description": "Supports bulk CREATE operations" + }, + "bulkUpdate": { + "type": "boolean", + "default": false, + "description": "Supports bulk UPDATE operations" + }, + "bulkDelete": { + "type": "boolean", + "default": false, + "description": "Supports bulk DELETE operations" + }, + "transactions": { + "type": "boolean", + "default": false, + "description": "Supports ACID transactions" + }, + "savepoints": { + "type": "boolean", + "default": false, + "description": "Supports transaction savepoints" + }, + "isolationLevels": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "read-uncommitted", + "read-committed", + "repeatable-read", + "serializable" + ] + }, + "description": "Supported transaction isolation levels" + }, + "queryFilters": { + "type": "boolean", + "default": true, + "description": "Supports WHERE clause filtering" + }, + "queryAggregations": { + "type": "boolean", + "default": false, + "description": "Supports GROUP BY and aggregation functions" + }, + "querySorting": { + "type": "boolean", + "default": true, + "description": "Supports ORDER BY sorting" + }, + "queryPagination": { + "type": "boolean", + "default": true, + "description": "Supports LIMIT/OFFSET pagination" + }, + "queryWindowFunctions": { + "type": "boolean", + "default": false, + "description": "Supports window functions with OVER clause" + }, + "querySubqueries": { + "type": "boolean", + "default": false, + "description": "Supports subqueries" + }, + "queryCTE": { + "type": "boolean", + "default": false, + "description": "Supports Common Table Expressions (WITH clause)" + }, + "joins": { + "type": "boolean", + "default": false, + "description": "Supports SQL joins" + }, + "fullTextSearch": { + "type": "boolean", + "default": false, + "description": "Supports full-text search" + }, + "jsonQuery": { + "type": "boolean", + "default": false, + "description": "Supports JSON field querying" + }, + "geospatialQuery": { + "type": "boolean", + "default": false, + "description": "Supports geospatial queries" + }, + "streaming": { + "type": "boolean", + "default": false, + "description": "Supports result streaming (cursors/iterators)" + }, + "jsonFields": { + "type": "boolean", + "default": false, + "description": "Supports JSON field types" + }, + "arrayFields": { + "type": "boolean", + "default": false, + "description": "Supports array field types" + }, + "vectorSearch": { + "type": "boolean", + "default": false, + "description": "Supports vector embeddings and similarity search" + }, + "geoSpatial": { + "type": "boolean", + "default": false, + "description": "Supports geospatial queries (deprecated: use geospatialQuery)" + }, + "schemaSync": { + "type": "boolean", + "default": false, + "description": "Supports automatic schema synchronization" + }, + "migrations": { + "type": "boolean", + "default": false, + "description": "Supports database migrations" + }, + "indexes": { + "type": "boolean", + "default": false, + "description": "Supports index creation and management" + }, + "connectionPooling": { + "type": "boolean", + "default": false, + "description": "Supports connection pooling" + }, + "preparedStatements": { + "type": "boolean", + "default": false, + "description": "Supports prepared statements (SQL injection prevention)" + }, + "queryCache": { + "type": "boolean", + "default": false, + "description": "Supports query result caching" + } + }, + "additionalProperties": false, + "description": "Driver capability flags" + }, + "connectionString": { + "type": "string", + "description": "Database connection string (driver-specific format)" + }, + "poolConfig": { + "type": "object", + "properties": { + "min": { + "type": "number", + "minimum": 0, + "default": 2, + "description": "Minimum number of connections in pool" + }, + "max": { + "type": "number", + "minimum": 1, + "default": 10, + "description": "Maximum number of connections in pool" + }, + "idleTimeoutMillis": { + "type": "number", + "minimum": 0, + "default": 30000, + "description": "Time in ms before idle connection is closed" + }, + "connectionTimeoutMillis": { + "type": "number", + "minimum": 0, + "default": 5000, + "description": "Time in ms to wait for available connection" + } + }, + "additionalProperties": false, + "description": "Connection pool configuration" + }, + "dialect": { + "type": "string", + "enum": [ + "postgresql", + "mysql", + "sqlite", + "mssql", + "oracle", + "mariadb" + ], + "description": "SQL database dialect" + }, + "dataTypeMapping": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "SQL type for text fields (e.g., VARCHAR, TEXT)" + }, + "number": { + "type": "string", + "description": "SQL type for number fields (e.g., NUMERIC, DECIMAL, INT)" + }, + "boolean": { + "type": "string", + "description": "SQL type for boolean fields (e.g., BOOLEAN, BIT)" + }, + "date": { + "type": "string", + "description": "SQL type for date fields (e.g., DATE)" + }, + "datetime": { + "type": "string", + "description": "SQL type for datetime fields (e.g., TIMESTAMP, DATETIME)" + }, + "json": { + "type": "string", + "description": "SQL type for JSON fields (e.g., JSON, JSONB)" + }, + "uuid": { + "type": "string", + "description": "SQL type for UUID fields (e.g., UUID, CHAR(36))" + }, + "binary": { + "type": "string", + "description": "SQL type for binary fields (e.g., BLOB, BYTEA)" + } + }, + "required": [ + "text", + "number", + "boolean", + "date", + "datetime" + ], + "additionalProperties": false, + "description": "SQL data type mapping configuration" + }, + "ssl": { + "type": "boolean", + "default": false, + "description": "Enable SSL/TLS connection" + }, + "sslConfig": { + "type": "object", + "properties": { + "rejectUnauthorized": { + "type": "boolean", + "default": true, + "description": "Reject connections with invalid certificates" + }, + "ca": { + "type": "string", + "description": "CA certificate file path or content" + }, + "cert": { + "type": "string", + "description": "Client certificate file path or content" + }, + "key": { + "type": "string", + "description": "Client private key file path or content" + } + }, + "additionalProperties": false, + "description": "SSL/TLS configuration (required when ssl is true)" + } + }, + "required": [ + "name", + "type", + "capabilities", + "dialect", + "dataTypeMapping" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/SSLConfig.json b/packages/spec/json-schema/system/SSLConfig.json new file mode 100644 index 000000000..39d7bc903 --- /dev/null +++ b/packages/spec/json-schema/system/SSLConfig.json @@ -0,0 +1,29 @@ +{ + "$ref": "#/definitions/SSLConfig", + "definitions": { + "SSLConfig": { + "type": "object", + "properties": { + "rejectUnauthorized": { + "type": "boolean", + "default": true, + "description": "Reject connections with invalid certificates" + }, + "ca": { + "type": "string", + "description": "CA certificate file path or content" + }, + "cert": { + "type": "string", + "description": "Client certificate file path or content" + }, + "key": { + "type": "string", + "description": "Client private key file path or content" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ui/FieldWidgetProps.json b/packages/spec/json-schema/ui/FieldWidgetProps.json index b9862fddb..6ce31c3f1 100644 --- a/packages/spec/json-schema/ui/FieldWidgetProps.json +++ b/packages/spec/json-schema/ui/FieldWidgetProps.json @@ -625,6 +625,226 @@ "additionalProperties": false, "description": "Configuration for file and attachment field types" }, + "encryptionConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "algorithm": { + "type": "string", + "enum": [ + "aes-256-gcm", + "aes-256-cbc", + "chacha20-poly1305" + ], + "default": "aes-256-gcm" + }, + "keyManagement": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "enum": [ + "local", + "aws-kms", + "azure-key-vault", + "gcp-kms", + "hashicorp-vault" + ] + }, + "keyId": { + "type": "string" + }, + "rotationPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "frequencyDays": { + "type": "number", + "minimum": 1, + "default": 90 + }, + "retainOldVersions": { + "type": "number", + "default": 3 + }, + "autoRotate": { + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + } + }, + "required": [ + "provider" + ], + "additionalProperties": false + }, + "scope": { + "type": "string", + "enum": [ + "field", + "record", + "table", + "database" + ] + }, + "deterministicEncryption": { + "type": "boolean", + "default": false, + "description": "Allows equality queries on encrypted data" + }, + "searchableEncryption": { + "type": "boolean", + "default": false, + "description": "Allows search on encrypted data" + } + }, + "required": [ + "keyManagement", + "scope" + ], + "additionalProperties": false, + "description": "Field-level encryption configuration for sensitive data (GDPR/HIPAA/PCI-DSS)" + }, + "maskingRule": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "strategy": { + "type": "string", + "enum": [ + "redact", + "partial", + "hash", + "tokenize", + "randomize", + "nullify", + "substitute" + ] + }, + "pattern": { + "type": "string", + "description": "Regex pattern for partial masking" + }, + "preserveFormat": { + "type": "boolean", + "default": true + }, + "preserveLength": { + "type": "boolean", + "default": true + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Roles that see masked data" + }, + "exemptRoles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Roles that see unmasked data" + } + }, + "required": [ + "field", + "strategy" + ], + "additionalProperties": false, + "description": "Data masking rules for PII protection" + }, + "auditTrail": { + "type": "boolean", + "default": false, + "description": "Enable detailed audit trail for this field (tracks all changes with user and timestamp)" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of field names that this field depends on (for formulas, visibility rules, etc.)" + }, + "cached": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable caching for computed field results" + }, + "ttl": { + "type": "number", + "minimum": 0, + "description": "Cache TTL in seconds (0 = no expiration)" + }, + "invalidateOn": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field paths that invalidate cache (e.g., [\"inventory.quantity\", \"pricing.base_price\"])" + } + }, + "required": [ + "enabled", + "ttl", + "invalidateOn" + ], + "additionalProperties": false, + "description": "Caching configuration for computed/formula fields" + }, + "dataQuality": { + "type": "object", + "properties": { + "uniqueness": { + "type": "boolean", + "default": false, + "description": "Enforce unique values across all records" + }, + "completeness": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 0, + "description": "Minimum ratio of non-null values (0-1, default: 0 = no requirement)" + }, + "accuracy": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Reference data source for validation (e.g., \"api.verify.com\", \"master_data\")" + }, + "threshold": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Minimum accuracy threshold (0-1, e.g., 0.95 = 95% match required)" + } + }, + "required": [ + "source", + "threshold" + ], + "additionalProperties": false, + "description": "Accuracy validation configuration" + } + }, + "additionalProperties": false, + "description": "Data quality validation and monitoring rules" + }, "hidden": { "type": "boolean", "default": false, @@ -638,7 +858,7 @@ "encryption": { "type": "boolean", "default": false, - "description": "Encrypt at rest" + "description": "Deprecated: Use encryptionConfig for enhanced encryption features. Simple flag for backward compatibility." }, "index": { "type": "boolean", diff --git a/packages/spec/src/data/field.zod.ts b/packages/spec/src/data/field.zod.ts index 2212c3ef0..8e9d2544a 100644 --- a/packages/spec/src/data/field.zod.ts +++ b/packages/spec/src/data/field.zod.ts @@ -1,5 +1,7 @@ import { z } from 'zod'; import { SystemIdentifierSchema } from '../shared/identifiers.zod'; +import { EncryptionConfigSchema } from '../system/encryption.zod'; +import { MaskingRuleSchema } from '../system/masking.zod'; /** * Field Type Enum @@ -259,6 +261,56 @@ export const FileAttachmentConfigSchema = z.object({ message: 'virusScanProvider requires virusScan to be enabled', }); +/** + * Data Quality Rules Schema + * Defines data quality validation and monitoring for fields + * + * @example Unique SSN field with completeness requirement + * { + * uniqueness: true, + * completeness: 0.95, // 95% of records must have this field + * accuracy: { + * source: 'government_db', + * threshold: 0.98 + * } + * } + */ +export const DataQualityRulesSchema = z.object({ + /** Enforce uniqueness constraint */ + uniqueness: z.boolean().default(false).describe('Enforce unique values across all records'), + + /** Completeness ratio (0-1) indicating minimum percentage of non-null values */ + completeness: z.number().min(0).max(1).default(0).describe('Minimum ratio of non-null values (0-1, default: 0 = no requirement)'), + + /** Accuracy validation against authoritative source */ + accuracy: z.object({ + source: z.string().describe('Reference data source for validation (e.g., "api.verify.com", "master_data")'), + threshold: z.number().min(0).max(1).describe('Minimum accuracy threshold (0-1, e.g., 0.95 = 95% match required)'), + }).optional().describe('Accuracy validation configuration'), +}); + +/** + * Computed Field Caching Schema + * Configuration for caching computed/formula field results + * + * @example Cache product price with 1-hour TTL, invalidate on inventory changes + * { + * enabled: true, + * ttl: 3600, + * invalidateOn: ['inventory.quantity', 'pricing.discount'] + * } + */ +export const ComputedFieldCacheSchema = z.object({ + /** Enable caching for this computed field */ + enabled: z.boolean().describe('Enable caching for computed field results'), + + /** Time-to-live in seconds */ + ttl: z.number().min(0).describe('Cache TTL in seconds (0 = no expiration)'), + + /** Array of field paths that trigger cache invalidation when changed */ + invalidateOn: z.array(z.string()).describe('Field paths that invalidate cache (e.g., ["inventory.quantity", "pricing.base_price"])'), +}); + /** * Field Schema - Best Practice Enterprise Pattern */ @@ -349,10 +401,32 @@ export const FieldSchema = z.object({ // File attachment field config fileAttachmentConfig: FileAttachmentConfigSchema.optional().describe('Configuration for file and attachment field types'), + /** Enhanced Security & Compliance */ + // Encryption configuration + encryptionConfig: EncryptionConfigSchema.optional().describe('Field-level encryption configuration for sensitive data (GDPR/HIPAA/PCI-DSS)'), + + // Data masking rules + maskingRule: MaskingRuleSchema.optional().describe('Data masking rules for PII protection'), + + // Audit trail + auditTrail: z.boolean().default(false).describe('Enable detailed audit trail for this field (tracks all changes with user and timestamp)'), + + /** Field Dependencies & Relationships */ + // Field dependencies + dependencies: z.array(z.string()).optional().describe('Array of field names that this field depends on (for formulas, visibility rules, etc.)'), + + /** Computed Field Optimization */ + // Computed field caching + cached: ComputedFieldCacheSchema.optional().describe('Caching configuration for computed/formula fields'), + + /** Data Quality & Governance */ + // Data quality rules + dataQuality: DataQualityRulesSchema.optional().describe('Data quality validation and monitoring rules'), + /** Security & Visibility */ hidden: z.boolean().default(false).describe('Hidden from default UI'), readonly: z.boolean().default(false).describe('Read-only in UI'), - encryption: z.boolean().default(false).describe('Encrypt at rest'), + encryption: z.boolean().default(false).describe('Deprecated: Use encryptionConfig for enhanced encryption features. Simple flag for backward compatibility.'), /** Indexing */ index: z.boolean().default(false).describe('Create standard database index'), @@ -367,6 +441,8 @@ export type CurrencyConfig = z.infer; export type CurrencyValue = z.infer; export type VectorConfig = z.infer; export type FileAttachmentConfig = z.infer; +export type DataQualityRules = z.infer; +export type ComputedFieldCache = z.infer; /** * Field Factory Helper diff --git a/packages/spec/src/data/object.zod.ts b/packages/spec/src/data/object.zod.ts index 22a991f60..e5e71149b 100644 --- a/packages/spec/src/data/object.zod.ts +++ b/packages/spec/src/data/object.zod.ts @@ -59,12 +59,14 @@ export const ObjectCapabilities = z.object({ /** * Schema for database indexes. + * Enhanced with additional index types and configuration options */ export const IndexSchema = z.object({ - name: z.string().optional().describe('Index name'), + name: z.string().optional().describe('Index name (auto-generated if not provided)'), fields: z.array(z.string()).describe('Fields included in the index'), - unique: z.boolean().optional().describe('Whether the index is unique'), - type: z.enum(['btree', 'hash', 'gin', 'gist']).optional().describe('Index type (default: btree)'), + type: z.enum(['btree', 'hash', 'gin', 'gist', 'fulltext']).optional().default('btree').describe('Index algorithm type'), + unique: z.boolean().optional().default(false).describe('Whether the index enforces uniqueness'), + partial: z.string().optional().describe('Partial index condition (SQL WHERE clause for conditional indexes)'), }); /** @@ -77,6 +79,105 @@ export const SearchConfigSchema = z.object({ filters: z.array(z.string()).optional().describe('Default filters for search results'), }); +/** + * Multi-Tenancy Configuration Schema + * Configures tenant isolation strategy for SaaS applications + * + * @example Shared database with tenant_id isolation + * { + * enabled: true, + * strategy: 'shared', + * tenantField: 'tenant_id', + * crossTenantAccess: false + * } + */ +export const TenancyConfigSchema = z.object({ + enabled: z.boolean().describe('Enable multi-tenancy for this object'), + strategy: z.enum(['shared', 'isolated', 'hybrid']).describe('Tenant isolation strategy: shared (single DB, row-level), isolated (separate DB per tenant), hybrid (mix)'), + tenantField: z.string().default('tenant_id').describe('Field name for tenant identifier'), + crossTenantAccess: z.boolean().default(false).describe('Allow cross-tenant data access (with explicit permission)'), +}); + +/** + * Soft Delete Configuration Schema + * Implements recycle bin / trash functionality + * + * @example Standard soft delete with cascade + * { + * enabled: true, + * field: 'deleted_at', + * cascadeDelete: true + * } + */ +export const SoftDeleteConfigSchema = z.object({ + enabled: z.boolean().describe('Enable soft delete (trash/recycle bin)'), + field: z.string().default('deleted_at').describe('Field name for soft delete timestamp'), + cascadeDelete: z.boolean().default(false).describe('Cascade soft delete to related records'), +}); + +/** + * Versioning Configuration Schema + * Implements record versioning and history tracking + * + * @example Snapshot versioning with 90-day retention + * { + * enabled: true, + * strategy: 'snapshot', + * retentionDays: 90, + * versionField: 'version' + * } + */ +export const VersioningConfigSchema = z.object({ + enabled: z.boolean().describe('Enable record versioning'), + strategy: z.enum(['snapshot', 'delta', 'event-sourcing']).describe('Versioning strategy: snapshot (full copy), delta (changes only), event-sourcing (event log)'), + retentionDays: z.number().min(1).optional().describe('Number of days to retain old versions (undefined = infinite)'), + versionField: z.string().default('version').describe('Field name for version number/timestamp'), +}); + +/** + * Partitioning Strategy Schema + * Configures table partitioning for performance at scale + * + * @example Range partitioning by date (monthly) + * { + * enabled: true, + * strategy: 'range', + * key: 'created_at', + * interval: '1 month' + * } + */ +export const PartitioningConfigSchema = z.object({ + enabled: z.boolean().describe('Enable table partitioning'), + strategy: z.enum(['range', 'hash', 'list']).describe('Partitioning strategy: range (date ranges), hash (consistent hashing), list (predefined values)'), + key: z.string().describe('Field name to partition by'), + interval: z.string().optional().describe('Partition interval for range strategy (e.g., "1 month", "1 year")'), +}).refine((data) => { + // If strategy is 'range', interval must be provided + if (data.strategy === 'range' && !data.interval) { + return false; + } + return true; +}, { + message: 'interval is required when strategy is "range"', +}); + +/** + * Change Data Capture (CDC) Configuration Schema + * Enables real-time data streaming to external systems + * + * @example Stream all changes to Kafka + * { + * enabled: true, + * events: ['insert', 'update', 'delete'], + * destination: 'kafka://events.objectstack' + * } + */ +export const CDCConfigSchema = z.object({ + enabled: z.boolean().describe('Enable Change Data Capture'), + events: z.array(z.enum(['insert', 'update', 'delete'])).describe('Event types to capture'), + destination: z.string().describe('Destination endpoint (e.g., "kafka://topic", "webhook://url")'), +}); + /** * Base Object Schema Definition * @@ -113,6 +214,25 @@ const ObjectSchemaBase = z.object({ fields: z.record(FieldSchema).describe('Field definitions map'), indexes: z.array(IndexSchema).optional().describe('Database performance indexes'), + /** + * Advanced Data Management + */ + + // Multi-tenancy configuration + tenancy: TenancyConfigSchema.optional().describe('Multi-tenancy configuration for SaaS applications'), + + // Soft delete configuration + softDelete: SoftDeleteConfigSchema.optional().describe('Soft delete (trash/recycle bin) configuration'), + + // Versioning configuration + versioning: VersioningConfigSchema.optional().describe('Record versioning and history tracking configuration'), + + // Partitioning strategy + partitioning: PartitioningConfigSchema.optional().describe('Table partitioning configuration for performance'), + + // Change Data Capture + cdc: CDCConfigSchema.optional().describe('Change Data Capture (CDC) configuration for real-time data streaming'), + /** * Logic & Validation (Co-located) * Best Practice: Define rules close to data. @@ -146,3 +266,8 @@ export const ObjectSchema = Object.assign(ObjectSchemaBase, { export type ServiceObject = z.infer; export type ObjectCapabilities = z.infer; export type ObjectIndex = z.infer; +export type TenancyConfig = z.infer; +export type SoftDeleteConfig = z.infer; +export type VersioningConfig = z.infer; +export type PartitioningConfig = z.infer; +export type CDCConfig = z.infer; diff --git a/packages/spec/src/system/driver-sql.test.ts b/packages/spec/src/system/driver-sql.test.ts new file mode 100644 index 000000000..fbb2d1d16 --- /dev/null +++ b/packages/spec/src/system/driver-sql.test.ts @@ -0,0 +1,392 @@ +import { describe, it, expect } from 'vitest'; +import { + SQLDialectSchema, + DataTypeMappingSchema, + SSLConfigSchema, + SQLDriverConfigSchema, + type SQLDialect, + type DataTypeMapping, + type SSLConfig, + type SQLDriverConfig, +} from './driver-sql.zod'; + +describe('SQLDialectSchema', () => { + it('should accept valid SQL dialects', () => { + const validDialects = [ + 'postgresql', + 'mysql', + 'sqlite', + 'mssql', + 'oracle', + 'mariadb', + ]; + + validDialects.forEach(dialect => { + expect(() => SQLDialectSchema.parse(dialect)).not.toThrow(); + }); + }); + + it('should reject invalid SQL dialects', () => { + expect(() => SQLDialectSchema.parse('mongodb')).toThrow(); + expect(() => SQLDialectSchema.parse('redis')).toThrow(); + expect(() => SQLDialectSchema.parse('')).toThrow(); + }); +}); + +describe('DataTypeMappingSchema', () => { + it('should accept valid PostgreSQL data type mapping', () => { + const mapping: DataTypeMapping = { + text: 'VARCHAR(255)', + number: 'NUMERIC', + boolean: 'BOOLEAN', + date: 'DATE', + datetime: 'TIMESTAMP', + json: 'JSONB', + uuid: 'UUID', + binary: 'BYTEA', + }; + + expect(() => DataTypeMappingSchema.parse(mapping)).not.toThrow(); + }); + + it('should accept MySQL data type mapping without optional fields', () => { + const mapping: DataTypeMapping = { + text: 'VARCHAR(255)', + number: 'DECIMAL(10,2)', + boolean: 'TINYINT(1)', + date: 'DATE', + datetime: 'DATETIME', + }; + + expect(() => DataTypeMappingSchema.parse(mapping)).not.toThrow(); + }); + + it('should require basic data type mappings', () => { + const incomplete = { + text: 'VARCHAR(255)', + // missing required fields + }; + + const result = DataTypeMappingSchema.safeParse(incomplete); + expect(result.success).toBe(false); + }); +}); + +describe('SSLConfigSchema', () => { + it('should accept SSL configuration with all fields', () => { + const sslConfig: SSLConfig = { + rejectUnauthorized: true, + ca: '/path/to/ca.pem', + cert: '/path/to/cert.pem', + key: '/path/to/key.pem', + }; + + expect(() => SSLConfigSchema.parse(sslConfig)).not.toThrow(); + }); + + it('should accept minimal SSL configuration', () => { + const sslConfig: SSLConfig = { + rejectUnauthorized: false, + }; + + expect(() => SSLConfigSchema.parse(sslConfig)).not.toThrow(); + }); + + it('should use default for rejectUnauthorized', () => { + const sslConfig = { + ca: '/path/to/ca.pem', + }; + + const result = SSLConfigSchema.parse(sslConfig); + expect(result.rejectUnauthorized).toBe(true); + }); + + it('should reject SSL config with cert but no key', () => { + const sslConfig = { + cert: '/path/to/cert.pem', + // missing key + }; + + const result = SSLConfigSchema.safeParse(sslConfig); + expect(result.success).toBe(false); + }); + + it('should reject SSL config with key but no cert', () => { + const sslConfig = { + key: '/path/to/key.pem', + // missing cert + }; + + const result = SSLConfigSchema.safeParse(sslConfig); + expect(result.success).toBe(false); + }); + + it('should accept SSL config with both cert and key', () => { + const sslConfig = { + cert: '/path/to/cert.pem', + key: '/path/to/key.pem', + }; + + const result = SSLConfigSchema.safeParse(sslConfig); + expect(result.success).toBe(true); + }); +}); + +describe('SQLDriverConfigSchema', () => { + it('should accept complete PostgreSQL driver configuration', () => { + const config: SQLDriverConfig = { + name: 'primary-db', + type: 'sql', + dialect: 'postgresql', + connectionString: 'postgresql://user:pass@localhost:5432/mydb', + dataTypeMapping: { + text: 'VARCHAR(255)', + number: 'NUMERIC', + boolean: 'BOOLEAN', + date: 'DATE', + datetime: 'TIMESTAMP', + json: 'JSONB', + uuid: 'UUID', + binary: 'BYTEA', + }, + ssl: true, + sslConfig: { + rejectUnauthorized: true, + ca: '/etc/ssl/certs/ca.pem', + }, + poolConfig: { + min: 2, + max: 10, + idleTimeoutMillis: 30000, + connectionTimeoutMillis: 5000, + }, + capabilities: { + create: true, + read: true, + update: true, + delete: true, + bulkCreate: true, + bulkUpdate: true, + bulkDelete: true, + transactions: true, + savepoints: true, + isolationLevels: ['read-committed', 'repeatable-read', 'serializable'], + queryFilters: true, + queryAggregations: true, + querySorting: true, + queryPagination: true, + queryWindowFunctions: true, + querySubqueries: true, + queryCTE: true, + joins: true, + fullTextSearch: true, + jsonQuery: true, + geospatialQuery: false, + streaming: true, + jsonFields: true, + arrayFields: true, + vectorSearch: true, + geoSpatial: false, + schemaSync: true, + migrations: true, + indexes: true, + connectionPooling: true, + preparedStatements: true, + queryCache: false, + }, + }; + + expect(() => SQLDriverConfigSchema.parse(config)).not.toThrow(); + }); + + it('should accept MySQL driver configuration', () => { + const config: SQLDriverConfig = { + name: 'mysql-db', + type: 'sql', + dialect: 'mysql', + connectionString: 'mysql://user:pass@localhost:3306/mydb', + dataTypeMapping: { + text: 'VARCHAR(255)', + number: 'DECIMAL(10,2)', + boolean: 'TINYINT(1)', + date: 'DATE', + datetime: 'DATETIME', + json: 'JSON', + binary: 'BLOB', + }, + ssl: false, + capabilities: { + create: true, + read: true, + update: true, + delete: true, + bulkCreate: true, + bulkUpdate: true, + bulkDelete: true, + transactions: true, + savepoints: true, + queryFilters: true, + queryAggregations: true, + querySorting: true, + queryPagination: true, + queryWindowFunctions: true, + querySubqueries: true, + queryCTE: true, + joins: true, + fullTextSearch: true, + jsonQuery: true, + geospatialQuery: false, + streaming: false, + jsonFields: true, + arrayFields: false, + vectorSearch: false, + geoSpatial: false, + schemaSync: true, + migrations: true, + indexes: true, + connectionPooling: true, + preparedStatements: true, + queryCache: false, + }, + }; + + expect(() => SQLDriverConfigSchema.parse(config)).not.toThrow(); + }); + + it('should require type to be "sql"', () => { + const config = { + name: 'test-db', + type: 'nosql', // wrong type + dialect: 'postgresql', + dataTypeMapping: { + text: 'VARCHAR(255)', + number: 'NUMERIC', + boolean: 'BOOLEAN', + date: 'DATE', + datetime: 'TIMESTAMP', + }, + capabilities: {}, + }; + + const result = SQLDriverConfigSchema.safeParse(config); + expect(result.success).toBe(false); + }); + + it('should require dialect field', () => { + const config = { + name: 'test-db', + type: 'sql', + // missing dialect + dataTypeMapping: { + text: 'VARCHAR(255)', + number: 'NUMERIC', + boolean: 'BOOLEAN', + date: 'DATE', + datetime: 'TIMESTAMP', + }, + capabilities: {}, + }; + + const result = SQLDriverConfigSchema.safeParse(config); + expect(result.success).toBe(false); + }); + + it('should accept SQLite driver configuration without SSL', () => { + const config: SQLDriverConfig = { + name: 'sqlite-db', + type: 'sql', + dialect: 'sqlite', + connectionString: ':memory:', + dataTypeMapping: { + text: 'TEXT', + number: 'REAL', + boolean: 'INTEGER', + date: 'TEXT', + datetime: 'TEXT', + }, + ssl: false, + capabilities: { + create: true, + read: true, + update: true, + delete: true, + bulkCreate: false, + bulkUpdate: false, + bulkDelete: false, + transactions: true, + savepoints: true, + queryFilters: true, + queryAggregations: true, + querySorting: true, + queryPagination: true, + queryWindowFunctions: true, + querySubqueries: true, + queryCTE: true, + joins: true, + fullTextSearch: true, + jsonQuery: true, + geospatialQuery: false, + streaming: false, + jsonFields: true, + arrayFields: false, + vectorSearch: false, + geoSpatial: false, + schemaSync: true, + migrations: false, + indexes: true, + connectionPooling: false, + preparedStatements: true, + queryCache: false, + }, + }; + + expect(() => SQLDriverConfigSchema.parse(config)).not.toThrow(); + }); + + it('should reject SQL driver config with ssl=true but no sslConfig', () => { + const config = { + name: 'test-db', + type: 'sql', + dialect: 'postgresql', + connectionString: 'postgresql://localhost/test', + dataTypeMapping: { + text: 'VARCHAR(255)', + number: 'NUMERIC', + boolean: 'BOOLEAN', + date: 'DATE', + datetime: 'TIMESTAMP', + }, + ssl: true, + // missing sslConfig + capabilities: {}, + }; + + const result = SQLDriverConfigSchema.safeParse(config); + expect(result.success).toBe(false); + }); + + it('should accept SQL driver config with ssl=true and sslConfig provided', () => { + const config = { + name: 'test-db', + type: 'sql', + dialect: 'postgresql', + connectionString: 'postgresql://localhost/test', + dataTypeMapping: { + text: 'VARCHAR(255)', + number: 'NUMERIC', + boolean: 'BOOLEAN', + date: 'DATE', + datetime: 'TIMESTAMP', + }, + ssl: true, + sslConfig: { + rejectUnauthorized: true, + ca: '/path/to/ca.pem', + }, + capabilities: {}, + }; + + const result = SQLDriverConfigSchema.safeParse(config); + expect(result.success).toBe(true); + }); +}); diff --git a/packages/spec/src/system/driver-sql.zod.ts b/packages/spec/src/system/driver-sql.zod.ts new file mode 100644 index 000000000..0335f30b7 --- /dev/null +++ b/packages/spec/src/system/driver-sql.zod.ts @@ -0,0 +1,159 @@ +import { z } from 'zod'; +import { DriverConfigSchema } from './driver.zod'; + +/** + * SQL Dialect Enumeration + * Supported SQL database dialects + */ +export const SQLDialectSchema = z.enum([ + 'postgresql', + 'mysql', + 'sqlite', + 'mssql', + 'oracle', + 'mariadb', +]); + +export type SQLDialect = z.infer; + +/** + * Data Type Mapping Schema + * Maps ObjectStack field types to SQL-specific data types + * + * @example PostgreSQL data type mapping + * { + * text: 'VARCHAR(255)', + * number: 'NUMERIC', + * boolean: 'BOOLEAN', + * date: 'DATE', + * datetime: 'TIMESTAMP', + * json: 'JSONB', + * uuid: 'UUID', + * binary: 'BYTEA' + * } + */ +export const DataTypeMappingSchema = z.object({ + text: z.string().describe('SQL type for text fields (e.g., VARCHAR, TEXT)'), + number: z.string().describe('SQL type for number fields (e.g., NUMERIC, DECIMAL, INT)'), + boolean: z.string().describe('SQL type for boolean fields (e.g., BOOLEAN, BIT)'), + date: z.string().describe('SQL type for date fields (e.g., DATE)'), + datetime: z.string().describe('SQL type for datetime fields (e.g., TIMESTAMP, DATETIME)'), + json: z.string().optional().describe('SQL type for JSON fields (e.g., JSON, JSONB)'), + uuid: z.string().optional().describe('SQL type for UUID fields (e.g., UUID, CHAR(36))'), + binary: z.string().optional().describe('SQL type for binary fields (e.g., BLOB, BYTEA)'), +}); + +export type DataTypeMapping = z.infer; + +/** + * SSL Configuration Schema + * SSL/TLS connection configuration for secure database connections + * + * @example PostgreSQL SSL configuration + * { + * rejectUnauthorized: true, + * ca: '/path/to/ca-cert.pem', + * cert: '/path/to/client-cert.pem', + * key: '/path/to/client-key.pem' + * } + */ +export const SSLConfigSchema = z.object({ + rejectUnauthorized: z.boolean().default(true).describe('Reject connections with invalid certificates'), + ca: z.string().optional().describe('CA certificate file path or content'), + cert: z.string().optional().describe('Client certificate file path or content'), + key: z.string().optional().describe('Client private key file path or content'), +}).refine((data) => { + // If cert is provided, key must also be provided, and vice versa + const hasCert = data.cert !== undefined; + const hasKey = data.key !== undefined; + return hasCert === hasKey; +}, { + message: 'Client certificate (cert) and private key (key) must be provided together', +}); + +export type SSLConfig = z.infer; + +/** + * SQL Driver Configuration Schema + * Extended driver configuration specific to SQL databases + * + * @example PostgreSQL driver configuration + * { + * name: 'primary-db', + * type: 'sql', + * dialect: 'postgresql', + * connectionString: 'postgresql://user:pass@localhost:5432/mydb', + * dataTypeMapping: { + * text: 'VARCHAR(255)', + * number: 'NUMERIC', + * boolean: 'BOOLEAN', + * date: 'DATE', + * datetime: 'TIMESTAMP', + * json: 'JSONB', + * uuid: 'UUID', + * binary: 'BYTEA' + * }, + * ssl: true, + * sslConfig: { + * rejectUnauthorized: true, + * ca: '/etc/ssl/certs/ca.pem' + * }, + * poolConfig: { + * min: 2, + * max: 10, + * idleTimeoutMillis: 30000, + * connectionTimeoutMillis: 5000 + * }, + * capabilities: { + * create: true, + * read: true, + * update: true, + * delete: true, + * bulkCreate: true, + * bulkUpdate: true, + * bulkDelete: true, + * transactions: true, + * savepoints: true, + * isolationLevels: ['read-committed', 'repeatable-read', 'serializable'], + * queryFilters: true, + * queryAggregations: true, + * querySorting: true, + * queryPagination: true, + * queryWindowFunctions: true, + * querySubqueries: true, + * queryCTE: true, + * joins: true, + * fullTextSearch: true, + * jsonQuery: true, + * geospatialQuery: false, + * streaming: true, + * jsonFields: true, + * arrayFields: true, + * vectorSearch: true, + * geoSpatial: false, + * schemaSync: true, + * migrations: true, + * indexes: true, + * connectionPooling: true, + * preparedStatements: true, + * queryCache: false + * } + * } + */ +export const SQLDriverConfigSchema = DriverConfigSchema.extend({ + type: z.literal('sql').describe('Driver type must be "sql"'), + dialect: SQLDialectSchema.describe('SQL database dialect'), + dataTypeMapping: DataTypeMappingSchema.describe('SQL data type mapping configuration'), + ssl: z.boolean().default(false).describe('Enable SSL/TLS connection'), + sslConfig: SSLConfigSchema.optional().describe('SSL/TLS configuration (required when ssl is true)'), +}).refine((data) => { + // If ssl is enabled, sslConfig must be provided + if (data.ssl && !data.sslConfig) { + return false; + } + return true; +}, { + message: 'sslConfig is required when ssl is true', +}); + +export type SQLDriverConfig = z.infer; diff --git a/packages/spec/src/system/driver.test.ts b/packages/spec/src/system/driver.test.ts index b4e678af2..1b0cd2458 100644 --- a/packages/spec/src/system/driver.test.ts +++ b/packages/spec/src/system/driver.test.ts @@ -43,16 +43,22 @@ describe('DriverCapabilitiesSchema', () => { expect(() => DriverCapabilitiesSchema.parse(capabilities)).not.toThrow(); }); - it('should require all capability flags', () => { + it('should accept capabilities with defaults', () => { const incomplete = { transactions: true, joins: true, queryFilters: true, - // missing other fields + // missing other fields - they should use defaults }; const result = DriverCapabilitiesSchema.safeParse(incomplete); - expect(result.success).toBe(false); + expect(result.success).toBe(true); + if (result.success) { + // Check that defaults are applied + expect(result.data.create).toBe(true); // default + expect(result.data.bulkCreate).toBe(false); // default + expect(result.data.queryAggregations).toBe(false); // default + } }); }); diff --git a/packages/spec/src/system/driver.zod.ts b/packages/spec/src/system/driver.zod.ts index d709ea05f..14456e2f4 100644 --- a/packages/spec/src/system/driver.zod.ts +++ b/packages/spec/src/system/driver.zod.ts @@ -40,8 +40,52 @@ export const DriverOptionsSchema = z.object({ * * Defines what features a database driver supports. * This allows ObjectQL to adapt its behavior based on underlying database capabilities. + * Enhanced with granular capability flags for better feature detection. */ export const DriverCapabilitiesSchema = z.object({ + // ============================================================================ + // Basic CRUD Operations + // ============================================================================ + + /** + * Whether the driver supports create operations. + */ + create: z.boolean().default(true).describe('Supports CREATE operations'), + + /** + * Whether the driver supports read operations. + */ + read: z.boolean().default(true).describe('Supports READ operations'), + + /** + * Whether the driver supports update operations. + */ + update: z.boolean().default(true).describe('Supports UPDATE operations'), + + /** + * Whether the driver supports delete operations. + */ + delete: z.boolean().default(true).describe('Supports DELETE operations'), + + // ============================================================================ + // Bulk Operations + // ============================================================================ + + /** + * Whether the driver supports bulk create operations. + */ + bulkCreate: z.boolean().default(false).describe('Supports bulk CREATE operations'), + + /** + * Whether the driver supports bulk update operations. + */ + bulkUpdate: z.boolean().default(false).describe('Supports bulk UPDATE operations'), + + /** + * Whether the driver supports bulk delete operations. + */ + bulkDelete: z.boolean().default(false).describe('Supports bulk DELETE operations'), + // ============================================================================ // Transaction & Connection Management // ============================================================================ @@ -50,7 +94,22 @@ export const DriverCapabilitiesSchema = z.object({ * Whether the driver supports database transactions. * If true, beginTransaction, commit, and rollback must be implemented. */ - transactions: z.boolean().describe('Supports transactions'), + transactions: z.boolean().default(false).describe('Supports ACID transactions'), + + /** + * Whether the driver supports savepoints within transactions. + */ + savepoints: z.boolean().default(false).describe('Supports transaction savepoints'), + + /** + * Supported transaction isolation levels. + */ + isolationLevels: z.array(z.enum([ + 'read-uncommitted', + 'read-committed', + 'repeatable-read', + 'serializable', + ])).optional().describe('Supported transaction isolation levels'), // ============================================================================ // Query Operations @@ -62,43 +121,48 @@ export const DriverCapabilitiesSchema = z.object({ * * Example: Memory driver might not support complex filter conditions. */ - queryFilters: z.boolean().describe('Supports WHERE clause filtering'), + queryFilters: z.boolean().default(true).describe('Supports WHERE clause filtering'), /** * Whether the driver supports aggregation functions (COUNT, SUM, AVG, etc.). * If false, ObjectQL will compute aggregations in memory. */ - queryAggregations: z.boolean().describe('Supports GROUP BY and aggregation functions'), + queryAggregations: z.boolean().default(false).describe('Supports GROUP BY and aggregation functions'), /** * Whether the driver supports ORDER BY sorting. * If false, ObjectQL will sort results in memory. */ - querySorting: z.boolean().describe('Supports ORDER BY sorting'), + querySorting: z.boolean().default(true).describe('Supports ORDER BY sorting'), /** * Whether the driver supports LIMIT/OFFSET pagination. * If false, ObjectQL will fetch all records and paginate in memory. */ - queryPagination: z.boolean().describe('Supports LIMIT/OFFSET pagination'), + queryPagination: z.boolean().default(true).describe('Supports LIMIT/OFFSET pagination'), /** * Whether the driver supports window functions (ROW_NUMBER, RANK, LAG, LEAD, etc.). * If false, ObjectQL will compute window functions in memory. */ - queryWindowFunctions: z.boolean().describe('Supports window functions with OVER clause'), + queryWindowFunctions: z.boolean().default(false).describe('Supports window functions with OVER clause'), /** * Whether the driver supports subqueries (nested SELECT statements). * If false, ObjectQL will execute queries separately and combine results. */ - querySubqueries: z.boolean().describe('Supports subqueries'), + querySubqueries: z.boolean().default(false).describe('Supports subqueries'), + + /** + * Whether the driver supports Common Table Expressions (WITH clause). + */ + queryCTE: z.boolean().default(false).describe('Supports Common Table Expressions (WITH clause)'), /** * Whether the driver supports SQL-style joins. * If false, ObjectQL will fetch related data separately and join in memory. */ - joins: z.boolean().describe('Supports SQL joins'), + joins: z.boolean().default(false).describe('Supports SQL joins'), // ============================================================================ // Advanced Features @@ -108,19 +172,34 @@ export const DriverCapabilitiesSchema = z.object({ * Whether the driver supports full-text search. * If true, text search queries can be pushed to the database. */ - fullTextSearch: z.boolean().describe('Supports full-text search'), + fullTextSearch: z.boolean().default(false).describe('Supports full-text search'), + + /** + * Whether the driver supports JSON querying capabilities. + */ + jsonQuery: z.boolean().default(false).describe('Supports JSON field querying'), + + /** + * Whether the driver supports geospatial queries. + */ + geospatialQuery: z.boolean().default(false).describe('Supports geospatial queries'), + + /** + * Whether the driver supports streaming large result sets. + */ + streaming: z.boolean().default(false).describe('Supports result streaming (cursors/iterators)'), /** * Whether the driver supports JSON field types. * If false, JSON data will be serialized as strings. */ - jsonFields: z.boolean().describe('Supports JSON field types'), + jsonFields: z.boolean().default(false).describe('Supports JSON field types'), /** * Whether the driver supports array field types. * If false, arrays will be stored as JSON strings or in separate tables. */ - arrayFields: z.boolean().describe('Supports array field types'), + arrayFields: z.boolean().default(false).describe('Supports array field types'), /** * Whether the driver supports vector embeddings and similarity search. @@ -130,8 +209,55 @@ export const DriverCapabilitiesSchema = z.object({ /** * Whether the driver supports geospatial queries. + * @deprecated Use geospatialQuery instead + */ + geoSpatial: z.boolean().default(false).describe('Supports geospatial queries (deprecated: use geospatialQuery)'), + + // ============================================================================ + // Schema Management + // ============================================================================ + + /** + * Whether the driver supports automatic schema synchronization. + */ + schemaSync: z.boolean().default(false).describe('Supports automatic schema synchronization'), + + /** + * Whether the driver supports database migrations. + */ + migrations: z.boolean().default(false).describe('Supports database migrations'), + + /** + * Whether the driver supports index management. */ - geoSpatial: z.boolean().default(false).describe('Supports geospatial queries'), + indexes: z.boolean().default(false).describe('Supports index creation and management'), + + // ============================================================================ + // Performance & Optimization + // ============================================================================ + + /** + * Whether the driver supports connection pooling. + */ + connectionPooling: z.boolean().default(false).describe('Supports connection pooling'), + + /** + * Whether the driver supports prepared statements. + */ + preparedStatements: z.boolean().default(false).describe('Supports prepared statements (SQL injection prevention)'), + + /** + * Whether the driver supports query result caching. + */ + queryCache: z.boolean().default(false).describe('Supports query result caching'), +}).refine((data) => { + // Ensure deprecated geoSpatial and new geospatialQuery are consistent if both are provided + if (data.geoSpatial !== undefined && data.geospatialQuery !== undefined && data.geoSpatial !== data.geospatialQuery) { + return false; + } + return true; +}, { + message: 'Deprecated geoSpatial and geospatialQuery must have the same value if both are provided', }); /** @@ -486,9 +612,34 @@ export const DriverInterfaceSchema = z.object({ .optional(), }); +/** + * Connection Pool Configuration Schema + * Manages database connection pooling for performance + */ +export const PoolConfigSchema = z.object({ + min: z.number().min(0).default(2).describe('Minimum number of connections in pool'), + max: z.number().min(1).default(10).describe('Maximum number of connections in pool'), + idleTimeoutMillis: z.number().min(0).default(30000).describe('Time in ms before idle connection is closed'), + connectionTimeoutMillis: z.number().min(0).default(5000).describe('Time in ms to wait for available connection'), +}); + +/** + * Driver Configuration Schema + * Base configuration for database drivers + */ +export const DriverConfigSchema = z.object({ + name: z.string().describe('Driver instance name'), + type: z.enum(['sql', 'nosql', 'cache', 'search', 'graph', 'timeseries']).describe('Driver type category'), + capabilities: DriverCapabilitiesSchema.describe('Driver capability flags'), + connectionString: z.string().optional().describe('Database connection string (driver-specific format)'), + poolConfig: PoolConfigSchema.optional().describe('Connection pool configuration'), +}); + /** * TypeScript types */ export type DriverOptions = z.infer; export type DriverCapabilities = z.infer; export type DriverInterface = z.infer; +export type DriverConfig = z.infer; +export type PoolConfig = z.infer; diff --git a/packages/spec/src/system/index.ts b/packages/spec/src/system/index.ts index dc1353808..f4213679b 100644 --- a/packages/spec/src/system/index.ts +++ b/packages/spec/src/system/index.ts @@ -31,6 +31,7 @@ export * from './datasource.zod'; // Driver Protocol export * from './driver.zod'; +export * from './driver-sql.zod'; export * from './driver/mongo.zod'; export * from './driver/postgres.zod';