@deessejs/collections 0.0.51 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +204 -0
- package/dist/index.js +868 -22
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +821 -0
- package/dist/index.mjs.map +1 -0
- package/dist/next/index.js +421 -51
- package/dist/next/index.js.map +1 -0
- package/dist/next/index.mjs +377 -0
- package/dist/next/index.mjs.map +1 -0
- package/package.json +76 -72
- package/dist/collections/define.d.ts +0 -43
- package/dist/collections/define.js +0 -13
- package/dist/collections/extend-fields.d.ts +0 -3
- package/dist/collections/extend-fields.js +0 -13
- package/dist/collections/index.d.ts +0 -1
- package/dist/collections/index.js +0 -17
- package/dist/collections/types.d.ts +0 -29
- package/dist/collections/types.js +0 -2
- package/dist/config/index.d.ts +0 -2
- package/dist/config/index.js +0 -45
- package/dist/config/orchestrator.d.ts +0 -8
- package/dist/config/orchestrator.js +0 -70
- package/dist/config/types.d.ts +0 -14
- package/dist/config/types.js +0 -2
- package/dist/database/types.d.ts +0 -10
- package/dist/database/types.js +0 -2
- package/dist/drizzle/generate.d.ts +0 -2
- package/dist/drizzle/generate.js +0 -49
- package/dist/drizzle/index.d.ts +0 -31
- package/dist/drizzle/index.js +0 -24
- package/dist/drizzle/types.js +0 -1
- package/dist/dsl/collections.d.ts +0 -13
- package/dist/dsl/collections.js +0 -14
- package/dist/dsl/index.d.ts +0 -1
- package/dist/dsl/index.js +0 -17
- package/dist/dsl/types.d.ts +0 -1
- package/dist/dsl/types.js +0 -2
- package/dist/esm/collections/define.d.ts +0 -43
- package/dist/esm/collections/define.js +0 -9
- package/dist/esm/collections/extend-fields.d.ts +0 -3
- package/dist/esm/collections/extend-fields.js +0 -9
- package/dist/esm/collections/index.d.ts +0 -1
- package/dist/esm/collections/index.js +0 -1
- package/dist/esm/collections/types.d.ts +0 -29
- package/dist/esm/collections/types.js +0 -1
- package/dist/esm/config/index.d.ts +0 -5
- package/dist/esm/config/index.js +0 -13
- package/dist/esm/config/orchestrator.d.ts +0 -8
- package/dist/esm/config/orchestrator.js +0 -66
- package/dist/esm/config/types.d.ts +0 -14
- package/dist/esm/config/types.js +0 -1
- package/dist/esm/database/types.d.ts +0 -10
- package/dist/esm/database/types.js +0 -1
- package/dist/esm/drizzle/generate.d.ts +0 -2
- package/dist/esm/drizzle/generate.js +0 -30
- package/dist/esm/drizzle/index.d.ts +0 -31
- package/dist/esm/drizzle/index.js +0 -20
- package/dist/esm/drizzle/types.d.ts +0 -0
- package/dist/esm/drizzle/types.js +0 -1
- package/dist/esm/dsl/collections.d.ts +0 -13
- package/dist/esm/dsl/collections.js +0 -10
- package/dist/esm/dsl/index.d.ts +0 -1
- package/dist/esm/dsl/index.js +0 -1
- package/dist/esm/fields/constraints.d.ts +0 -6
- package/dist/esm/fields/constraints.js +0 -59
- package/dist/esm/fields/core.d.ts +0 -71
- package/dist/esm/fields/core.js +0 -27
- package/dist/esm/fields/field.d.ts +0 -24
- package/dist/esm/fields/field.js +0 -33
- package/dist/esm/fields/index.d.ts +0 -4
- package/dist/esm/fields/index.js +0 -4
- package/dist/esm/fields/types.d.ts +0 -48
- package/dist/esm/fields/types.js +0 -1
- package/dist/esm/index.d.ts +0 -8
- package/dist/esm/index.js +0 -8
- package/dist/esm/next/index.d.ts +0 -5
- package/dist/esm/next/index.js +0 -17
- package/dist/esm/plugins/index.d.ts +0 -2
- package/dist/esm/plugins/index.js +0 -3
- package/dist/esm/plugins/types.d.ts +0 -1
- package/dist/esm/plugins/types.js +0 -1
- package/dist/esm/providers/index.d.ts +0 -2
- package/dist/esm/providers/index.js +0 -53
- package/dist/esm/providers/types.d.ts +0 -8
- package/dist/esm/providers/types.js +0 -1
- package/dist/esm/utils/deep-partial.d.ts +0 -3
- package/dist/esm/utils/deep-partial.js +0 -1
- package/dist/esm/utils/exact.d.ts +0 -1
- package/dist/esm/utils/exact.js +0 -1
- package/dist/esm/utils/union-intersection.d.ts +0 -1
- package/dist/esm/utils/union-intersection.js +0 -1
- package/dist/esm/worker/index.d.ts +0 -2
- package/dist/esm/worker/index.js +0 -32
- package/dist/fields/constraints.d.ts +0 -6
- package/dist/fields/constraints.js +0 -67
- package/dist/fields/core.d.ts +0 -71
- package/dist/fields/core.js +0 -33
- package/dist/fields/field.d.ts +0 -24
- package/dist/fields/field.js +0 -38
- package/dist/fields/index.d.ts +0 -4
- package/dist/fields/index.js +0 -20
- package/dist/fields/types.d.ts +0 -48
- package/dist/fields/types.js +0 -2
- package/dist/index.d.ts +0 -8
- package/dist/next/index.d.ts +0 -5
- package/dist/plugins/index.d.ts +0 -2
- package/dist/plugins/index.js +0 -7
- package/dist/plugins/types.d.ts +0 -1
- package/dist/plugins/types.js +0 -2
- package/dist/providers/index.d.ts +0 -2
- package/dist/providers/index.js +0 -57
- package/dist/providers/types.d.ts +0 -8
- package/dist/providers/types.js +0 -2
- package/dist/utils/deep-partial.d.ts +0 -3
- package/dist/utils/deep-partial.js +0 -2
- package/dist/utils/exact.d.ts +0 -1
- package/dist/utils/exact.js +0 -1
- package/dist/utils/union-intersection.d.ts +0 -1
- package/dist/utils/union-intersection.js +0 -2
- package/dist/worker/index.d.ts +0 -1
- package/dist/worker/index.js +0 -101
- /package/{dist/drizzle/types.d.ts → public/.gitkeep} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/next/index.ts","../../src/field-type.ts","../../src/field.ts","../../src/fields/f.ts","../../src/collection.ts","../../src/operations/collection-operations.ts","../../src/adapter.ts","../../src/schema.ts","../../src/config.ts"],"sourcesContent":["/**\r\n * Next.js integration module for @deessejs/collections\r\n *\r\n * Provides hot reload support and Next.js plugin for collections\r\n */\r\n\r\nimport type { NextConfig } from 'next'\r\nimport type { Collection } from '../collection'\r\nimport { resolve } from 'path'\r\nimport process from 'process'\r\n\r\n// Re-export types from core for convenience\r\nexport type {\r\n Collection,\r\n CollectionConfig,\r\n CollectionHooks,\r\n OperationType,\r\n CreateHookContext,\r\n UpdateHookContext,\r\n DeleteHookContext,\r\n ReadHookContext,\r\n OperationHookContext\r\n} from '../collection'\r\n\r\n// Re-export field types\r\nexport type { FieldDefinition, FieldOptions } from '../field'\r\nexport type { FieldTypeInstance } from '../field-type'\r\n\r\n// Re-export field types and utilities\r\nexport { field, f, defineConfig, pgAdapter, buildSchema, collection } from '../index'\r\n\r\n/**\r\n * Type for withCollections configuration\r\n */\r\nexport interface WithCollectionsOptions {\r\n /**\r\n * Path to the collections config file\r\n * @default './collections/config'\r\n */\r\n configPath?: string\r\n\r\n /**\r\n * Enable hot reload in development\r\n * @default true\r\n */\r\n hotReload?: boolean\r\n\r\n /**\r\n * Output directory for generated schema\r\n * @default './drizzle'\r\n */\r\n outputDir?: string\r\n\r\n /**\r\n * Enable debug logging\r\n * @default false\r\n */\r\n debug?: boolean\r\n}\r\n\r\n/**\r\n * Type for the Next.js config returned by withCollections\r\n */\r\nexport type WithCollectionsConfig = NextConfig & {\r\n collections?: {\r\n collections: Record<string, Collection>\r\n outputDir: string\r\n isProduction: boolean\r\n configPath: string\r\n }\r\n}\r\n\r\n/**\r\n * Check if we're running in development mode\r\n */\r\nfunction isDevelopment(): boolean {\r\n return process.env.NODE_ENV === 'development'\r\n}\r\n\r\n/**\r\n * Check if we're running in a build-time context\r\n */\r\nfunction isBuildTime(): boolean {\r\n return process.env.__NEXT_BUILD === '1' || process.env.TURBO_BUILD === '1' || process.env.VERCEL === '1'\r\n}\r\n\r\n/**\r\n * Debug logging function\r\n */\r\nfunction debugLog(enabled: boolean, ...args: unknown[]): void {\r\n if (enabled) console.debug('[collections/next]', ...args)\r\n}\r\n\r\n/**\r\n * Validate that a path is within the project directory\r\n */\r\nfunction validateConfigPath(configPath: string, debug: boolean): string {\r\n const projectRoot = process.cwd()\r\n const resolvedPath = resolve(projectRoot, configPath)\r\n const normalizedPath = resolvedPath.replace(/\\\\/g, '/')\r\n const normalizedRoot = projectRoot.replace(/\\\\/g, '/')\r\n\r\n if (!normalizedPath.startsWith(normalizedRoot + '/') && normalizedPath !== normalizedRoot) {\r\n throw new Error(`Config path must be within project directory: ${configPath}`)\r\n }\r\n\r\n debugLog(debug, 'Validated config path:', resolvedPath)\r\n return resolvedPath\r\n}\r\n\r\n/**\r\n * Extract collections from a loaded module\r\n */\r\nfunction extractCollectionsFromModule(module: Record<string, unknown>): Record<string, Collection> {\r\n const defaultExport = module.default as Record<string, unknown> | undefined\r\n const defaultCollections = defaultExport ? extractFromObject(defaultExport) : {}\r\n const namedCollections = extractFromObject(module)\r\n\r\n return { ...defaultCollections, ...namedCollections }\r\n}\r\n\r\nfunction extractFromObject(obj: Record<string, unknown>): Record<string, Collection> {\r\n const collections: Record<string, Collection> = {}\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (key !== 'default' && typeof value === 'object' && value !== null && 'slug' in value) {\r\n collections[key] = value as Collection\r\n }\r\n }\r\n return collections\r\n}\r\n\r\n/**\r\n * Load collections from a config file using dynamic import\r\n */\r\nasync function loadCollectionsFromConfig(configPath: string, debug: boolean): Promise<Record<string, Collection>> {\r\n try {\r\n const validatedPath = validateConfigPath(configPath, debug)\r\n const module = await import(/* @vite-ignore */ validatedPath)\r\n const collections = extractCollectionsFromModule(module as Record<string, unknown>)\r\n debugLog(debug, `Loaded ${Object.keys(collections).length} collections`)\r\n return collections\r\n } catch {\r\n return {}\r\n }\r\n}\r\n\r\n/**\r\n * Create a Next.js plugin that provides collections integration\r\n *\r\n * @example\r\n * // next.config.mjs\r\n * import { withCollections } from '@deessejs/collections/next'\r\n *\r\n * export default withCollections({\r\n * // Next.js config\r\n * })\r\n */\r\nexport async function withCollections(nextConfig: NextConfig, options: WithCollectionsOptions = {}): Promise<WithCollectionsConfig> {\r\n const { configPath = './collections/config', hotReload = true, outputDir = './drizzle', debug = false } = options\r\n const isProduction = !isDevelopment()\r\n const shouldHotReload = hotReload && isDevelopment() && !isBuildTime()\r\n\r\n const collections = await loadCollectionsFromConfig(configPath, debug)\r\n let webpackConfig: NextConfig['webpack']\r\n\r\n if (shouldHotReload && nextConfig.webpack) {\r\n webpackConfig = (cfg, ctx) => nextConfig.webpack!(cfg, ctx)\r\n }\r\n\r\n return { ...nextConfig, collections: { collections, outputDir, isProduction, configPath }, webpack: webpackConfig }\r\n}\r\n\r\n/**\r\n * Synchronous version of withCollections\r\n * @deprecated Use withCollections() instead\r\n */\r\nexport function withCollectionsSync(nextConfig: NextConfig, options: WithCollectionsOptions = {}): WithCollectionsConfig {\r\n const { configPath = './collections/config', hotReload = true, outputDir = './drizzle' } = options\r\n const isProduction = !isDevelopment()\r\n const shouldHotReload = hotReload && isDevelopment() && !isBuildTime()\r\n let webpackConfig: NextConfig['webpack']\r\n\r\n if (shouldHotReload && nextConfig.webpack) {\r\n webpackConfig = (cfg, ctx) => nextConfig.webpack!(cfg, ctx)\r\n }\r\n\r\n return { ...nextConfig, collections: { collections: {}, outputDir, isProduction, configPath }, webpack: webpackConfig }\r\n}\r\n\r\n/**\r\n * Get the collections configuration from the Next.js config\r\n */\r\nexport function getCollectionsConfig(nextConfig: WithCollectionsConfig) {\r\n return nextConfig.collections\r\n}\r\n\r\n/**\r\n * Load collections from a config file\r\n */\r\nexport async function loadCollections(configPath: string): Promise<Record<string, Collection>> {\r\n return loadCollectionsFromConfig(configPath, false)\r\n}\r\n\r\n/**\r\n * Extract collections from Next.js config\r\n */\r\nexport function getCollectionsFromConfig(nextConfig: WithCollectionsConfig): Record<string, Collection> {\r\n return nextConfig.collections?.collections ?? {}\r\n}\r\n\r\n/**\r\n * Type guard to check if a value is a valid Next.js config\r\n */\r\nexport function isNextConfig(config: unknown): config is NextConfig {\r\n if (!config || typeof config !== 'object') return false\r\n const cfg = config as Record<string, unknown>\r\n if ('reactStrictMode' in cfg && typeof cfg.reactStrictMode !== 'boolean') return false\r\n if ('swcMinify' in cfg && typeof cfg.swcMinify !== 'boolean') return false\r\n const validProps = ['reactStrictMode', 'swcMinify', 'trailingSlash', 'poweredByHeader', 'compress']\r\n return validProps.some(prop => prop in cfg)\r\n}\r\n\r\n/**\r\n * Type guard to check if withCollections was applied\r\n */\r\nexport function isCollectionsConfig(config: unknown): config is WithCollectionsConfig {\r\n if (!config || typeof config !== 'object') return false\r\n return (config as Record<string, unknown>).collections !== undefined\r\n}\r\n\r\n/**\r\n * Default withCollections options\r\n */\r\nexport const defaultWithCollectionsOptions: Required<WithCollectionsOptions> = {\r\n configPath: './collections/config',\r\n hotReload: true,\r\n outputDir: './drizzle',\r\n debug: false\r\n}\r\n","import { z } from 'zod'\r\n\r\n/**\r\n * A field type instance (already configured)\r\n */\r\nexport type FieldTypeInstance = {\r\n schema: z.ZodType\r\n database: unknown\r\n}\r\n\r\n/**\r\n * A field type creator (needs to be called to get instance)\r\n */\r\nexport type FieldTypeCreator = () => FieldTypeInstance\r\n\r\n/**\r\n * Field type configuration\r\n */\r\nexport type FieldTypeConfig = {\r\n schema: z.ZodType\r\n database?: unknown\r\n}\r\n\r\n/**\r\n * Creates a new field type\r\n *\r\n * @example\r\n * const text = fieldType({\r\n * schema: z.string(),\r\n * database: { type: 'text' }\r\n * })\r\n *\r\n * const textField = text() // Get instance\r\n */\r\nexport const fieldType = (config: FieldTypeConfig): (() => FieldTypeInstance) => {\r\n return () => ({\r\n schema: config.schema,\r\n database: config.database ?? {}\r\n })\r\n}\r\n","import type { FieldTypeInstance } from './field-type'\r\n\r\n/**\r\n * Field configuration options\r\n */\r\nexport type FieldOptions = {\r\n fieldType: FieldTypeInstance\r\n required?: boolean\r\n unique?: boolean\r\n indexed?: boolean\r\n default?: unknown\r\n label?: string\r\n description?: string\r\n}\r\n\r\n/**\r\n * Creates a field definition\r\n *\r\n * @example\r\n * name: field({ fieldType: text() })\r\n * email: field({ fieldType: email(), unique: true })\r\n */\r\nexport const field = (config: FieldOptions): FieldDefinition => {\r\n return {\r\n fieldType: config.fieldType,\r\n required: config.required ?? false,\r\n unique: config.unique ?? false,\r\n indexed: config.indexed ?? false,\r\n default: config.default,\r\n label: config.label,\r\n description: config.description\r\n }\r\n}\r\n\r\n/**\r\n * A field definition\r\n */\r\nexport type FieldDefinition = {\r\n fieldType: FieldTypeInstance\r\n required: boolean\r\n unique: boolean\r\n indexed: boolean\r\n default?: unknown\r\n label?: string\r\n description?: string\r\n}\r\n","import { fieldType, type FieldTypeInstance } from '../field-type'\r\nimport { z } from 'zod'\r\n\r\n/**\r\n * Derive the database type string from a Zod schema\r\n */\r\nconst getItemType = (itemSchema: z.ZodType): string => {\r\n if (itemSchema instanceof z.ZodString) return 'text'\r\n if (itemSchema instanceof z.ZodNumber) return 'integer'\r\n if (itemSchema instanceof z.ZodBoolean) return 'boolean'\r\n if (itemSchema instanceof z.ZodDate) return 'timestamp'\r\n if (itemSchema instanceof z.ZodEnum) return 'text'\r\n if (itemSchema instanceof z.ZodArray) return 'array'\r\n if (itemSchema instanceof z.ZodObject) return 'jsonb'\r\n return 'text'\r\n}\r\n\r\n/**\r\n * Field types namespace (like zod's z)\r\n */\r\nexport const f = {\r\n /**\r\n * Text field type\r\n */\r\n text: (): FieldTypeInstance => fieldType({\r\n schema: z.string(),\r\n database: { type: 'text' }\r\n })(),\r\n\r\n /**\r\n * Email field type with built-in validation\r\n */\r\n email: (): FieldTypeInstance => fieldType({\r\n schema: z.string().email(),\r\n database: { type: 'text' }\r\n })(),\r\n\r\n /**\r\n * URL field type with built-in validation\r\n */\r\n url: (): FieldTypeInstance => fieldType({\r\n schema: z.string().url(),\r\n database: { type: 'text' }\r\n })(),\r\n\r\n /**\r\n * Number field type\r\n */\r\n number: (): FieldTypeInstance => fieldType({\r\n schema: z.number(),\r\n database: { type: 'integer' }\r\n })(),\r\n\r\n /**\r\n * Boolean field type\r\n */\r\n boolean: (): FieldTypeInstance => fieldType({\r\n schema: z.boolean(),\r\n database: { type: 'boolean' }\r\n })(),\r\n\r\n /**\r\n * Date field type (date only, no time)\r\n */\r\n date: (): FieldTypeInstance => fieldType({\r\n schema: z.date(),\r\n database: { type: 'date' }\r\n })(),\r\n\r\n /**\r\n * Timestamp field type (date with time)\r\n */\r\n timestamp: (): FieldTypeInstance => fieldType({\r\n schema: z.date(),\r\n database: { type: 'timestamp' }\r\n })(),\r\n\r\n /**\r\n * Creates a select field type\r\n */\r\n select: <T extends readonly [string, ...string[]]>(\r\n options: T\r\n ): FieldTypeInstance => fieldType({\r\n schema: z.enum(options),\r\n database: { type: 'text' }\r\n })(),\r\n\r\n /**\r\n * JSON field type for storing JSON data\r\n */\r\n json: (schema?: z.ZodType): FieldTypeInstance => fieldType({\r\n schema: schema ?? z.any(),\r\n database: { type: 'jsonb' }\r\n })(),\r\n\r\n /**\r\n * Array field type for storing lists\r\n */\r\n array: (itemSchema: z.ZodType): FieldTypeInstance => fieldType({\r\n schema: z.array(itemSchema),\r\n database: { type: 'array', itemType: getItemType(itemSchema) }\r\n })(),\r\n\r\n /**\r\n * Creates a relation field type for foreign key relationships\r\n */\r\n relation: (options: {\r\n collection: string\r\n singular?: boolean\r\n many?: boolean\r\n through?: string\r\n }): FieldTypeInstance => {\r\n const isMany = options.many ?? false\r\n const isSingular = options.singular ?? false\r\n\r\n return fieldType({\r\n schema: isMany ? z.array(z.string()) : z.string(),\r\n database: {\r\n type: 'integer',\r\n references: options.collection,\r\n through: options.through,\r\n many: isMany,\r\n singular: isSingular\r\n }\r\n })()\r\n }\r\n}\r\n\r\n/**\r\n * @deprecated Use f.text() instead\r\n */\r\nexport const text = f.text\r\n\r\n/**\r\n * @deprecated Use f.email() instead\r\n */\r\nexport const email = f.email\r\n\r\n/**\r\n * @deprecated Use f.url() instead\r\n */\r\nexport const url = f.url\r\n\r\n/**\r\n * @deprecated Use f.number() instead\r\n */\r\nexport const number = f.number\r\n\r\n/**\r\n * @deprecated Use f.boolean() instead\r\n */\r\nexport const boolean = f.boolean\r\n\r\n/**\r\n * @deprecated Use f.date() instead\r\n */\r\nexport const date = f.date\r\n\r\n/**\r\n * @deprecated Use f.timestamp() instead\r\n */\r\nexport const timestamp = f.timestamp\r\n\r\n/**\r\n * @deprecated Use f.select() instead\r\n */\r\nexport const select = f.select\r\n\r\n/**\r\n * @deprecated Use f.json() instead\r\n */\r\nexport const json = f.json\r\n\r\n/**\r\n * @deprecated Use f.array() instead\r\n */\r\nexport const array = f.array\r\n\r\n/**\r\n * @deprecated Use f.relation() instead\r\n */\r\nexport const relation = f.relation\r\n\r\n/**\r\n * @deprecated Use f.relation instead\r\n */\r\nexport type RelationOptions = {\r\n collection: string\r\n singular?: boolean\r\n many?: boolean\r\n through?: string\r\n}\r\n","import type { FieldDefinition } from './field'\r\n\r\n/**\r\n * Collection configuration\r\n */\r\nexport type CollectionConfig<T extends Record<string, unknown> = Record<string, unknown>> = {\r\n slug: string\r\n name?: string\r\n fields: Record<string, FieldDefinition>\r\n hooks?: CollectionHooks\r\n dataType?: T\r\n}\r\n\r\n/**\r\n * Operation types\r\n */\r\nexport type OperationType = 'create' | 'update' | 'delete' | 'read'\r\n\r\n/**\r\n * Hook context base\r\n */\r\nexport type HookContextBase = {\r\n collection: string\r\n operation: OperationType\r\n}\r\n\r\n/**\r\n * Before/After Operation context\r\n */\r\nexport type OperationHookContext = HookContextBase & {\r\n data?: Record<string, unknown>\r\n where?: Record<string, unknown>\r\n result?: unknown\r\n}\r\n\r\n/**\r\n * Before/After Create context\r\n */\r\nexport type CreateHookContext = HookContextBase & {\r\n operation: 'create'\r\n data: Record<string, unknown>\r\n result?: unknown\r\n db?: unknown\r\n}\r\n\r\n/**\r\n * Before/After Update context\r\n */\r\nexport type UpdateHookContext = HookContextBase & {\r\n operation: 'update'\r\n data: Record<string, unknown>\r\n where: Record<string, unknown>\r\n previousData?: Record<string, unknown>\r\n result?: unknown\r\n db?: unknown\r\n}\r\n\r\n/**\r\n * Before/After Delete context\r\n */\r\nexport type DeleteHookContext = HookContextBase & {\r\n operation: 'delete'\r\n where: Record<string, unknown>\r\n previousData?: Record<string, unknown>\r\n result?: unknown\r\n db?: unknown\r\n}\r\n\r\n/**\r\n * Before/After Read context\r\n */\r\nexport type ReadHookContext = HookContextBase & {\r\n operation: 'read'\r\n query?: Record<string, unknown>\r\n result?: unknown[]\r\n db?: unknown\r\n}\r\n\r\n/**\r\n * Generic hook function type\r\n */\r\nexport type GenericHookFunction = (context: OperationHookContext) => Promise<void> | void\r\nexport type CreateHookFunction = (context: CreateHookContext) => Promise<void> | void\r\nexport type UpdateHookFunction = (context: UpdateHookContext) => Promise<void> | void\r\nexport type DeleteHookFunction = (context: DeleteHookContext) => Promise<void> | void\r\nexport type ReadHookFunction = (context: ReadHookContext) => Promise<void> | void\r\n\r\n/**\r\n * Collection hooks\r\n */\r\nexport type CollectionHooks = {\r\n beforeOperation?: GenericHookFunction[]\r\n afterOperation?: GenericHookFunction[]\r\n beforeCreate?: CreateHookFunction[]\r\n afterCreate?: CreateHookFunction[]\r\n beforeUpdate?: UpdateHookFunction[]\r\n afterUpdate?: UpdateHookFunction[]\r\n beforeDelete?: DeleteHookFunction[]\r\n afterDelete?: DeleteHookFunction[]\r\n beforeRead?: ReadHookFunction[]\r\n afterRead?: ReadHookFunction[]\r\n}\r\n\r\n/**\r\n * A collection definition\r\n */\r\nexport type Collection<T extends Record<string, unknown> = Record<string, unknown>> = {\r\n slug: string\r\n name?: string\r\n fields: Record<string, FieldDefinition>\r\n hooks?: CollectionHooks\r\n dataType?: T\r\n}\r\n\r\n/**\r\n * Creates a new collection\r\n *\r\n * @example\r\n * export const users = collection({\r\n * slug: 'users',\r\n * name: 'Users',\r\n * fields: {\r\n * name: field({ fieldType: text }),\r\n * email: field({ fieldType: email, unique: true })\r\n * }\r\n * })\r\n */\r\nexport const collection = <T extends Record<string, unknown> = Record<string, unknown>>(\r\n config: CollectionConfig<T>\r\n): Collection<T> => {\r\n return {\r\n slug: config.slug,\r\n name: config.name,\r\n fields: config.fields,\r\n hooks: config.hooks,\r\n dataType: config.dataType\r\n }\r\n}\r\n","/* eslint-disable @typescript-eslint/no-explicit-any */\r\nimport { eq, and, like, gt, gte, lt, lte, isNull, inArray, not, desc, asc } from 'drizzle-orm'\r\n\r\nimport type { Collection, CollectionHooks, CreateHookContext, UpdateHookContext, DeleteHookContext, ReadHookContext, OperationHookContext } from '../collection'\r\nimport type {\r\n FindManyOptions,\r\n FindUniqueOptions,\r\n FindFirstOptions,\r\n CreateOptions,\r\n CreateManyOptions,\r\n UpdateOptions,\r\n UpdateManyOptions,\r\n DeleteOptions,\r\n DeleteManyOptions,\r\n CountOptions,\r\n ExistsOptions,\r\n WhereOperator\r\n} from './types'\r\n\r\n/**\r\n * Collection operations interface\r\n */\r\nexport interface CollectionOperations {\r\n findMany<T>(options?: FindManyOptions): Promise<T[]>\r\n findUnique<T>(options: FindUniqueOptions): Promise<T | undefined>\r\n findFirst<T>(options: FindFirstOptions): Promise<T | undefined>\r\n create<T>(options: CreateOptions<T>): Promise<T | undefined>\r\n createMany<T>(options: CreateManyOptions<T>): Promise<number>\r\n update<T>(options: UpdateOptions<T>): Promise<T | undefined>\r\n updateMany<T>(options: UpdateManyOptions<T>): Promise<number>\r\n delete<T>(options: DeleteOptions): Promise<T | undefined>\r\n deleteMany(options: DeleteManyOptions): Promise<number>\r\n count(options?: CountOptions): Promise<number>\r\n exists(options: ExistsOptions): Promise<boolean>\r\n}\r\n\r\n/**\r\n * Build where conditions from options\r\n */\r\nconst buildWhereClause = (\r\n tableColumns: Record<string, any>,\r\n where?: Record<string, unknown>\r\n): any => {\r\n if (!where) return undefined\r\n\r\n const conditions: any[] = []\r\n\r\n for (const [key, value] of Object.entries(where)) {\r\n const column = tableColumns[key]\r\n if (!column) continue\r\n\r\n if (value === null || typeof value !== 'object') {\r\n conditions.push(eq(column, value))\r\n } else {\r\n const operator = value as WhereOperator<unknown>\r\n if ('eq' in operator) {\r\n conditions.push(eq(column, operator.eq))\r\n } else if ('neq' in operator) {\r\n conditions.push(not(eq(column, operator.neq)))\r\n } else if ('gt' in operator) {\r\n conditions.push(gt(column, operator.gt as number))\r\n } else if ('gte' in operator) {\r\n conditions.push(gte(column, operator.gte as number))\r\n } else if ('lt' in operator) {\r\n conditions.push(lt(column, operator.lt as number))\r\n } else if ('lte' in operator) {\r\n conditions.push(lte(column, operator.lte as number))\r\n } else if ('in' in operator) {\r\n conditions.push(inArray(column, operator.in))\r\n } else if ('notIn' in operator) {\r\n conditions.push(not(inArray(column, operator.notIn)))\r\n } else if ('contains' in operator) {\r\n conditions.push(like(column, `%${operator.contains}%`))\r\n } else if ('startsWith' in operator) {\r\n conditions.push(like(column, `${operator.startsWith}%`))\r\n } else if ('endsWith' in operator) {\r\n conditions.push(like(column, `%${operator.endsWith}`))\r\n } else if ('isNull' in operator) {\r\n if (operator.isNull) {\r\n conditions.push(isNull(column))\r\n }\r\n } else if ('not' in operator) {\r\n conditions.push(not(eq(column, operator.not)))\r\n }\r\n }\r\n }\r\n\r\n if (conditions.length === 0) return undefined\r\n if (conditions.length === 1) return conditions[0]\r\n return and(...conditions)\r\n}\r\n\r\n/**\r\n * Build orderBy from options\r\n */\r\nconst buildOrderBy = (\r\n tableColumns: Record<string, any>,\r\n orderBy?: Record<string, unknown> | Record<string, unknown>[]\r\n): any[] => {\r\n if (!orderBy) return []\r\n\r\n const orders = Array.isArray(orderBy) ? orderBy : [orderBy]\r\n return orders.map((order) => {\r\n for (const [key, direction] of Object.entries(order)) {\r\n const column = tableColumns[key]\r\n if (!column) continue\r\n return direction === 'desc' ? desc(column) : asc(column)\r\n }\r\n return undefined\r\n }).filter(Boolean)\r\n}\r\n\r\n/**\r\n * Execute before operation hooks\r\n */\r\nconst executeBeforeOperationHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: OperationHookContext\r\n): Promise<void> => {\r\n if (!hooks?.beforeOperation) return\r\n for (const hook of hooks.beforeOperation) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute after operation hooks\r\n */\r\nconst executeAfterOperationHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: OperationHookContext\r\n): Promise<void> => {\r\n if (!hooks?.afterOperation) return\r\n for (const hook of hooks.afterOperation) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute before create hooks\r\n */\r\nconst executeBeforeCreateHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: CreateHookContext\r\n): Promise<void> => {\r\n if (!hooks?.beforeCreate) return\r\n for (const hook of hooks.beforeCreate) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute after create hooks\r\n */\r\nconst executeAfterCreateHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: CreateHookContext\r\n): Promise<void> => {\r\n if (!hooks?.afterCreate) return\r\n for (const hook of hooks.afterCreate) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute before update hooks\r\n */\r\nconst executeBeforeUpdateHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: UpdateHookContext\r\n): Promise<void> => {\r\n if (!hooks?.beforeUpdate) return\r\n for (const hook of hooks.beforeUpdate) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute after update hooks\r\n */\r\nconst executeAfterUpdateHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: UpdateHookContext\r\n): Promise<void> => {\r\n if (!hooks?.afterUpdate) return\r\n for (const hook of hooks.afterUpdate) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute before delete hooks\r\n */\r\nconst executeBeforeDeleteHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: DeleteHookContext\r\n): Promise<void> => {\r\n if (!hooks?.beforeDelete) return\r\n for (const hook of hooks.beforeDelete) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute after delete hooks\r\n */\r\nconst executeAfterDeleteHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: DeleteHookContext\r\n): Promise<void> => {\r\n if (!hooks?.afterDelete) return\r\n for (const hook of hooks.afterDelete) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute before read hooks\r\n */\r\nconst executeBeforeReadHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: ReadHookContext\r\n): Promise<void> => {\r\n if (!hooks?.beforeRead) return\r\n for (const hook of hooks.beforeRead) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Execute after read hooks\r\n */\r\nconst executeAfterReadHooks = async (\r\n hooks: CollectionHooks | undefined,\r\n context: ReadHookContext\r\n): Promise<void> => {\r\n if (!hooks?.afterRead) return\r\n for (const hook of hooks.afterRead) {\r\n await hook(context)\r\n }\r\n}\r\n\r\n/**\r\n * Creates collection operations with Drizzle\r\n */\r\nexport const createCollectionOperations = (\r\n _collection: Collection,\r\n _slug: string,\r\n _db: any,\r\n _table: any,\r\n _hooks?: CollectionHooks\r\n): CollectionOperations => {\r\n const tableColumns = _table as Record<string, any>\r\n const db = _db as any\r\n const hooks = _hooks as CollectionHooks | undefined\r\n\r\n // If no db instance, return placeholder operations\r\n if (!db) {\r\n return {\r\n findMany: async <T>(): Promise<T[]> => [],\r\n findUnique: async <T>(): Promise<T | undefined> => undefined,\r\n findFirst: async <T>(): Promise<T | undefined> => undefined,\r\n create: async <T>(): Promise<T | undefined> => undefined,\r\n createMany: async (): Promise<number> => 0,\r\n update: async <T>(): Promise<T | undefined> => undefined,\r\n updateMany: async (): Promise<number> => 0,\r\n delete: async <T>(): Promise<T | undefined> => undefined,\r\n deleteMany: async (): Promise<number> => 0,\r\n count: async (): Promise<number> => 0,\r\n exists: async (): Promise<boolean> => false\r\n }\r\n }\r\n\r\n return {\r\n findMany: async <T>(options?: FindManyOptions): Promise<T[]> => {\r\n const whereClause = buildWhereClause(tableColumns, options?.where)\r\n const orderByClause = buildOrderBy(tableColumns, options?.orderBy)\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options?.where\r\n })\r\n\r\n // Execute before read hooks\r\n await executeBeforeReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n db\r\n })\r\n\r\n let query = db.select().from(_table)\r\n\r\n if (whereClause) {\r\n query = query.where(whereClause)\r\n }\r\n\r\n if (orderByClause.length > 0) {\r\n query = query.orderBy(...orderByClause)\r\n }\r\n\r\n if (options?.offset) {\r\n query = query.offset(options.offset)\r\n }\r\n\r\n if (options?.limit) {\r\n query = query.limit(options.limit)\r\n }\r\n\r\n const result = await query\r\n\r\n // Execute after read hooks\r\n await executeAfterReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n result: result as unknown[],\r\n db\r\n })\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options?.where,\r\n result\r\n })\r\n\r\n return result as T[]\r\n },\r\n\r\n findUnique: async <T>(options: FindUniqueOptions): Promise<T | undefined> => {\r\n const whereClause = buildWhereClause(tableColumns, options.where)\r\n if (!whereClause) return undefined\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options.where\r\n })\r\n\r\n // Execute before read hooks\r\n await executeBeforeReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n db\r\n })\r\n\r\n const result = await db.select().from(_table).where(whereClause).limit(1)\r\n const returnValue = result[0] as T | undefined\r\n\r\n // Execute after read hooks\r\n await executeAfterReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n result: returnValue ? [returnValue] : [],\r\n db\r\n })\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options.where,\r\n result: returnValue\r\n })\r\n\r\n return returnValue\r\n },\r\n\r\n findFirst: async <T>(options: FindFirstOptions): Promise<T | undefined> => {\r\n const whereClause = buildWhereClause(tableColumns, options.where)\r\n const orderByClause = buildOrderBy(tableColumns, options.orderBy)\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options.where\r\n })\r\n\r\n // Execute before read hooks\r\n await executeBeforeReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n db\r\n })\r\n\r\n let query = db.select().from(_table)\r\n\r\n if (whereClause) {\r\n query = query.where(whereClause)\r\n }\r\n\r\n if (orderByClause.length > 0) {\r\n query = query.orderBy(...orderByClause)\r\n }\r\n\r\n const result = await query.limit(1)\r\n const returnValue = result[0] as T | undefined\r\n\r\n // Execute after read hooks\r\n await executeAfterReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n result: returnValue ? [returnValue] : [],\r\n db\r\n })\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options.where,\r\n result: returnValue\r\n })\r\n\r\n return returnValue\r\n },\r\n\r\n create: async <T>(options: CreateOptions<T>): Promise<T | undefined> => {\r\n const data = Array.isArray(options.data) ? options.data : [options.data]\r\n const firstData = data[0] as Record<string, unknown>\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'create',\r\n data: firstData,\r\n where: undefined\r\n })\r\n\r\n // Execute before create hooks\r\n await executeBeforeCreateHooks(hooks, {\r\n collection: _slug,\r\n operation: 'create',\r\n data: firstData,\r\n db\r\n })\r\n\r\n const result = await db.insert(_table).values(data).returning()\r\n\r\n const returnValue = options.returning ? result[0] as T : undefined\r\n\r\n // Execute after create hooks\r\n await executeAfterCreateHooks(hooks, {\r\n collection: _slug,\r\n operation: 'create',\r\n data: firstData,\r\n result: returnValue,\r\n db\r\n })\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'create',\r\n data: firstData,\r\n result: returnValue\r\n })\r\n\r\n return returnValue\r\n },\r\n\r\n createMany: async <T>(options: CreateManyOptions<T>): Promise<number> => {\r\n const dataArray = Array.isArray(options.data) ? options.data : [options.data]\r\n\r\n // Execute before operation hooks for each item\r\n for (const data of dataArray) {\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'create',\r\n data: data as Record<string, unknown>,\r\n where: undefined\r\n })\r\n\r\n await executeBeforeCreateHooks(hooks, {\r\n collection: _slug,\r\n operation: 'create',\r\n data: data as Record<string, unknown>,\r\n db\r\n })\r\n }\r\n\r\n const result = await db.insert(_table).values(options.data as any)\r\n\r\n // Execute after operation hooks for each item\r\n for (let i = 0; i < dataArray.length; i++) {\r\n await executeAfterCreateHooks(hooks, {\r\n collection: _slug,\r\n operation: 'create',\r\n data: dataArray[i] as Record<string, unknown>,\r\n result: result[i],\r\n db\r\n })\r\n\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'create',\r\n data: dataArray[i] as Record<string, unknown>,\r\n result: result[i]\r\n })\r\n }\r\n\r\n return result.length || 0\r\n },\r\n\r\n update: async <T>(options: UpdateOptions<T>): Promise<T | undefined> => {\r\n const whereClause = buildWhereClause(tableColumns, options.where)\r\n if (!whereClause) return undefined\r\n\r\n // Get previous data for hooks\r\n const previousResult = await db.select().from(_table).where(whereClause).limit(1)\r\n const previousData = previousResult[0] as Record<string, unknown> | undefined\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'update',\r\n data: options.data as Record<string, unknown>,\r\n where: options.where\r\n })\r\n\r\n // Execute before update hooks\r\n await executeBeforeUpdateHooks(hooks, {\r\n collection: _slug,\r\n operation: 'update',\r\n data: options.data as Record<string, unknown>,\r\n where: options.where,\r\n previousData,\r\n db\r\n })\r\n\r\n const result = await db.update(_table)\r\n .set(options.data as any)\r\n .where(whereClause)\r\n .returning()\r\n\r\n const returnValue = options.returning ? result[0] as T : undefined\r\n\r\n // Execute after update hooks\r\n await executeAfterUpdateHooks(hooks, {\r\n collection: _slug,\r\n operation: 'update',\r\n data: options.data as Record<string, unknown>,\r\n where: options.where,\r\n previousData,\r\n result: returnValue,\r\n db\r\n })\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'update',\r\n data: options.data as Record<string, unknown>,\r\n where: options.where,\r\n result: returnValue\r\n })\r\n\r\n return returnValue\r\n },\r\n\r\n updateMany: async <T>(options: UpdateManyOptions<T>): Promise<number> => {\r\n const whereClause = buildWhereClause(tableColumns, options.where)\r\n if (!whereClause) return 0\r\n\r\n // Get previous data for hooks\r\n const previousResults = await db.select().from(_table).where(whereClause)\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'update',\r\n data: options.data as Record<string, unknown>,\r\n where: options.where\r\n })\r\n\r\n // Execute before update hooks (for each previous record)\r\n for (const previousData of previousResults) {\r\n await executeBeforeUpdateHooks(hooks, {\r\n collection: _slug,\r\n operation: 'update',\r\n data: options.data as Record<string, unknown>,\r\n where: options.where,\r\n previousData: previousData as Record<string, unknown>,\r\n db\r\n })\r\n }\r\n\r\n const result = await db.update(_table)\r\n .set(options.data as any)\r\n .where(whereClause)\r\n\r\n // Execute after update hooks\r\n for (const previousData of previousResults) {\r\n await executeAfterUpdateHooks(hooks, {\r\n collection: _slug,\r\n operation: 'update',\r\n data: options.data as Record<string, unknown>,\r\n where: options.where,\r\n previousData: previousData as Record<string, unknown>,\r\n db\r\n })\r\n }\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'update',\r\n data: options.data as Record<string, unknown>,\r\n where: options.where\r\n })\r\n\r\n return result.length || 0\r\n },\r\n\r\n delete: async <T>(options: DeleteOptions): Promise<T | undefined> => {\r\n const whereClause = buildWhereClause(tableColumns, options.where)\r\n if (!whereClause) return undefined\r\n\r\n // Get previous data for hooks\r\n const previousResult = await db.select().from(_table).where(whereClause).limit(1)\r\n const previousData = previousResult[0] as Record<string, unknown> | undefined\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'delete',\r\n where: options.where\r\n })\r\n\r\n // Execute before delete hooks\r\n await executeBeforeDeleteHooks(hooks, {\r\n collection: _slug,\r\n operation: 'delete',\r\n where: options.where,\r\n previousData,\r\n db\r\n })\r\n\r\n const result = await db.delete(_table)\r\n .where(whereClause)\r\n .returning()\r\n\r\n const returnValue = options.returning ? result[0] as T : undefined\r\n\r\n // Execute after delete hooks\r\n await executeAfterDeleteHooks(hooks, {\r\n collection: _slug,\r\n operation: 'delete',\r\n where: options.where,\r\n previousData,\r\n result: returnValue,\r\n db\r\n })\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'delete',\r\n where: options.where,\r\n result: returnValue\r\n })\r\n\r\n return returnValue\r\n },\r\n\r\n deleteMany: async (options: DeleteManyOptions): Promise<number> => {\r\n const whereClause = buildWhereClause(tableColumns, options.where)\r\n if (!whereClause) return 0\r\n\r\n // Get previous data for hooks\r\n const previousResults = await db.select().from(_table).where(whereClause)\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'delete',\r\n where: options.where\r\n })\r\n\r\n // Execute before delete hooks\r\n for (const previousData of previousResults) {\r\n await executeBeforeDeleteHooks(hooks, {\r\n collection: _slug,\r\n operation: 'delete',\r\n where: options.where,\r\n previousData: previousData as Record<string, unknown>,\r\n db\r\n })\r\n }\r\n\r\n const result = await db.delete(_table).where(whereClause)\r\n\r\n // Execute after delete hooks\r\n for (const previousData of previousResults) {\r\n await executeAfterDeleteHooks(hooks, {\r\n collection: _slug,\r\n operation: 'delete',\r\n where: options.where,\r\n previousData: previousData as Record<string, unknown>,\r\n db\r\n })\r\n }\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'delete',\r\n where: options.where\r\n })\r\n\r\n return result.length || 0\r\n },\r\n\r\n count: async (options?: CountOptions): Promise<number> => {\r\n const whereClause = buildWhereClause(tableColumns, options?.where)\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options?.where\r\n })\r\n\r\n // Execute before read hooks\r\n await executeBeforeReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n db\r\n })\r\n\r\n const result = whereClause\r\n ? await db.select().from(_table).where(whereClause)\r\n : await db.select().from(_table)\r\n\r\n // Execute after read hooks\r\n await executeAfterReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n result,\r\n db\r\n })\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options?.where,\r\n result\r\n })\r\n\r\n return result.length\r\n },\r\n\r\n exists: async (options: ExistsOptions): Promise<boolean> => {\r\n const whereClause = buildWhereClause(tableColumns, options.where)\r\n if (!whereClause) return false\r\n\r\n // Execute before operation hooks\r\n await executeBeforeOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options.where\r\n })\r\n\r\n // Execute before read hooks\r\n await executeBeforeReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n db\r\n })\r\n\r\n const result = await db.select().from(_table).where(whereClause).limit(1)\r\n const returnValue = result.length > 0\r\n\r\n // Execute after read hooks\r\n await executeAfterReadHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n query: options as unknown as Record<string, unknown>,\r\n result: result,\r\n db\r\n })\r\n\r\n // Execute after operation hooks\r\n await executeAfterOperationHooks(hooks, {\r\n collection: _slug,\r\n operation: 'read',\r\n where: options.where,\r\n result: returnValue\r\n })\r\n\r\n return returnValue\r\n }\r\n }\r\n}\r\n","/**\r\n * PostgreSQL adapter configuration\r\n */\r\nexport type PgAdapterConfig = {\r\n url: string\r\n migrationsPath?: string\r\n}\r\n\r\n/**\r\n * PostgreSQL adapter\r\n */\r\nexport interface PgAdapter {\r\n type: 'postgres'\r\n config: PgAdapterConfig\r\n}\r\n\r\n/**\r\n * Database adapter type\r\n */\r\nexport type DatabaseAdapter = PgAdapter\r\n\r\n/**\r\n * Creates a PostgreSQL adapter\r\n *\r\n * @example\r\n * const adapter = pgAdapter({\r\n * url: 'postgres://user:pass@localhost:5432/db'\r\n * })\r\n */\r\nexport const pgAdapter = (config: PgAdapterConfig): PgAdapter => {\r\n return {\r\n type: 'postgres',\r\n config: {\r\n url: config.url,\r\n migrationsPath: config.migrationsPath ?? './migrations'\r\n }\r\n }\r\n}\r\n","import { pgTable, serial, text, timestamp, uuid, varchar, boolean, integer } from 'drizzle-orm/pg-core'\r\n\r\nimport type { Collection } from './collection'\r\n\r\n/**\r\n * Build Drizzle table from collection definition\r\n */\r\nexport const buildTable = (collection: Collection) => {\r\n // Build columns object\r\n const columns: Record<string, unknown> = {\r\n // Add default id column\r\n id: serial('id').primaryKey()\r\n }\r\n\r\n // Build columns from fields\r\n for (const [fieldName, fieldDef] of Object.entries(collection.fields)) {\r\n // Skip the id field if explicitly defined in fields\r\n if (fieldName === 'id') continue\r\n\r\n const fieldType = fieldDef.fieldType as { name?: string; type?: string }\r\n const fieldTypeName = fieldType.name || fieldType.type || 'text'\r\n\r\n switch (fieldTypeName) {\r\n case 'text':\r\n columns[fieldName] = text(fieldName)\r\n break\r\n case 'varchar':\r\n columns[fieldName] = varchar(fieldName, { length: 255 })\r\n break\r\n case 'number':\r\n case 'integer':\r\n columns[fieldName] = integer(fieldName)\r\n break\r\n case 'boolean':\r\n columns[fieldName] = boolean(fieldName)\r\n break\r\n case 'timestamp':\r\n columns[fieldName] = timestamp(fieldName)\r\n break\r\n case 'uuid':\r\n columns[fieldName] = uuid(fieldName)\r\n break\r\n default:\r\n columns[fieldName] = text(fieldName)\r\n }\r\n }\r\n\r\n return pgTable(collection.slug, columns as Record<string, ReturnType<typeof text>>)\r\n}\r\n\r\n/**\r\n * Build all tables from collections\r\n */\r\nexport const buildSchema = (collections: Collection[]) => {\r\n const tables: Record<string, ReturnType<typeof pgTable>> = {}\r\n\r\n for (const coll of collections) {\r\n tables[coll.slug] = buildTable(coll)\r\n }\r\n\r\n return tables\r\n}\r\n","import { Pool, type Pool as PoolType } from 'pg'\r\nimport { drizzle } from 'drizzle-orm/node-postgres'\r\n\r\nimport type { Collection } from './collection'\r\nimport type { DatabaseAdapter } from './adapter'\r\nimport { buildSchema } from './schema'\r\n\r\n/**\r\n * Plugin interface\r\n */\r\nexport type Plugin = {\r\n name: string\r\n collections?: Record<string, Collection>\r\n hooks?: Record<string, unknown[]>\r\n}\r\n\r\n/**\r\n * Configuration options\r\n */\r\nexport type ConfigOptions<T extends Collection[] = []> = {\r\n database: DatabaseAdapter\r\n collections: T\r\n plugins?: Plugin[]\r\n}\r\n\r\n/**\r\n * Define config return type with inferred collection keys\r\n *\r\n * - collections: metadata only (slug, name, fields, hooks, dataType)\r\n * - db: Drizzle instance with operations (via schema tables)\r\n * - $meta: array of collection slugs and plugin names\r\n */\r\nexport type DefineConfigReturn<T extends Collection[] = []> = {\r\n collections: {\r\n [K in T[number] as K['slug']]: Collection\r\n }\r\n db: ReturnType<typeof drizzle<Record<string, unknown>>>\r\n $meta: {\r\n collections: T[number]['slug'][]\r\n plugins: string[]\r\n }\r\n}\r\n\r\n/**\r\n * Creates the configuration for the data layer\r\n *\r\n * @example\r\n * const adapter = pgAdapter({\r\n * url: process.env.DATABASE_URL!\r\n * })\r\n *\r\n * export const { collections, db } = defineConfig({\r\n * database: adapter,\r\n * collections: [users, posts],\r\n * plugins: [timestampsPlugin()]\r\n * })\r\n *\r\n * // collections: metadata only\r\n * collections.users.slug // 'users'\r\n * collections.users.fields // { name, email, ... }\r\n *\r\n * // db: Drizzle instance with operations\r\n * await db.users.findMany()\r\n * await db.users.insert(values)\r\n */\r\nexport const defineConfig = <T extends Collection[]>(\r\n options: ConfigOptions<T>\r\n): DefineConfigReturn<T> => {\r\n // Initialize the database connection based on adapter type\r\n let pool: PoolType | null = null\r\n let dbInstance: ReturnType<typeof drizzle<Record<string, unknown>>> | null = null\r\n\r\n let schema: Record<string, unknown> = {}\r\n\r\n if (options.database.type === 'postgres') {\r\n // Create pool from adapter config\r\n pool = new Pool({\r\n connectionString: options.database.config.url\r\n })\r\n\r\n // Build schema from collections\r\n schema = buildSchema(options.collections as Collection[])\r\n\r\n // Create Drizzle instance with schema\r\n dbInstance = drizzle(pool, { schema })\r\n }\r\n\r\n // Build collections map (metadata only)\r\n const collectionsMap: Record<string, Collection> = {}\r\n const collectionNames: string[] = []\r\n\r\n for (const coll of options.collections) {\r\n // Store only metadata (not operations)\r\n collectionsMap[coll.slug] = {\r\n slug: coll.slug,\r\n name: coll.name,\r\n fields: coll.fields,\r\n hooks: coll.hooks,\r\n dataType: coll.dataType\r\n }\r\n collectionNames.push(coll.slug)\r\n }\r\n\r\n // Build plugins map\r\n const pluginNames: string[] = []\r\n if (options.plugins) {\r\n for (const plugin of options.plugins) {\r\n pluginNames.push(plugin.name)\r\n\r\n // Register plugin collections (metadata only)\r\n if (plugin.collections) {\r\n for (const [name, coll] of Object.entries(plugin.collections)) {\r\n collectionsMap[name] = {\r\n slug: coll.slug,\r\n name: coll.name,\r\n fields: coll.fields,\r\n hooks: coll.hooks,\r\n dataType: coll.dataType\r\n }\r\n collectionNames.push(name)\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n collections: collectionsMap as DefineConfigReturn<T>['collections'],\r\n db: dbInstance as DefineConfigReturn<T>['db'],\r\n $meta: {\r\n collections: collectionNames as DefineConfigReturn<T>['$meta']['collections'],\r\n plugins: pluginNames\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["text","timestamp","boolean","collection","fieldType"]}
|
package/package.json
CHANGED
|
@@ -1,72 +1,76 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@deessejs/collections",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
}
|
|
72
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@deessejs/collections",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "High-level abstraction layer built on top of Drizzle ORM",
|
|
5
|
+
"readme": "README.md",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"public",
|
|
9
|
+
"LICENSE"
|
|
10
|
+
],
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"module": "./dist/index.mjs",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.mjs",
|
|
18
|
+
"require": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./fields": {
|
|
21
|
+
"types": "./dist/fields/index.d.ts",
|
|
22
|
+
"import": "./dist/fields/index.mjs",
|
|
23
|
+
"require": "./dist/fields/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./plugins": {
|
|
26
|
+
"types": "./dist/plugins/index.d.ts",
|
|
27
|
+
"import": "./dist/plugins/index.mjs",
|
|
28
|
+
"require": "./dist/plugins/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./next": {
|
|
31
|
+
"types": "./dist/next/index.d.ts",
|
|
32
|
+
"import": "./dist/next/index.mjs",
|
|
33
|
+
"require": "./dist/next/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"dev": "tsup --watch",
|
|
39
|
+
"lint": "eslint src/",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
43
|
+
"test:watch": "vitest",
|
|
44
|
+
"test:coverage": "vitest run --coverage"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"drizzle-kit": "^0.22.0",
|
|
48
|
+
"drizzle-orm": "^0.31.2",
|
|
49
|
+
"pg": "^8.11.0",
|
|
50
|
+
"zod": "^3.23.8"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@deessejs/type-testing": "^0.1.5",
|
|
54
|
+
"@neondatabase/serverless": "^1.0.2",
|
|
55
|
+
"@types/node": "^20.14.12",
|
|
56
|
+
"@types/pg": "^8.11.0",
|
|
57
|
+
"@types/react": "^18.3.0",
|
|
58
|
+
"next": "^14.2.0",
|
|
59
|
+
"react": "^18.3.0",
|
|
60
|
+
"eslint": "^8.57.0",
|
|
61
|
+
"neon-serverless": "^0.5.3",
|
|
62
|
+
"tsup": "^8.2.2",
|
|
63
|
+
"tsx": "^4.21.0",
|
|
64
|
+
"typescript": "^5.5.4",
|
|
65
|
+
"vitest": "^2.0.5"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"next": ">=14",
|
|
69
|
+
"react": ">=18",
|
|
70
|
+
"typescript": ">=5"
|
|
71
|
+
},
|
|
72
|
+
"publishConfig": {
|
|
73
|
+
"access": "public",
|
|
74
|
+
"registry": "https://registry.npmjs.org/"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { Field } from "../fields";
|
|
2
|
-
import { Collection } from "./types";
|
|
3
|
-
export declare const collection: <const Slug extends string, const Fields extends Record<string, Field>>(config: Collection<Slug, Fields>) => Collection<Slug, Fields & {
|
|
4
|
-
readonly id: Field<{
|
|
5
|
-
kind: import("../fields").FieldKind;
|
|
6
|
-
params: unknown;
|
|
7
|
-
dsl: {
|
|
8
|
-
kind: import("../fields").FieldKind;
|
|
9
|
-
isPrimary: boolean;
|
|
10
|
-
isUnique: boolean;
|
|
11
|
-
canBeNull: boolean;
|
|
12
|
-
};
|
|
13
|
-
admin: {
|
|
14
|
-
component: any;
|
|
15
|
-
};
|
|
16
|
-
}>;
|
|
17
|
-
readonly createdAt: import("../fields").FieldChain<{
|
|
18
|
-
kind: import("../fields").FieldKind;
|
|
19
|
-
params: unknown;
|
|
20
|
-
dsl: {
|
|
21
|
-
kind: import("../fields").FieldKind;
|
|
22
|
-
isPrimary: boolean;
|
|
23
|
-
isUnique: boolean;
|
|
24
|
-
canBeNull: boolean;
|
|
25
|
-
};
|
|
26
|
-
admin: {
|
|
27
|
-
component: any;
|
|
28
|
-
};
|
|
29
|
-
}>;
|
|
30
|
-
readonly updatedAt: import("../fields").FieldChain<{
|
|
31
|
-
kind: import("../fields").FieldKind;
|
|
32
|
-
params: unknown;
|
|
33
|
-
dsl: {
|
|
34
|
-
kind: import("../fields").FieldKind;
|
|
35
|
-
isPrimary: boolean;
|
|
36
|
-
isUnique: boolean;
|
|
37
|
-
canBeNull: boolean;
|
|
38
|
-
};
|
|
39
|
-
admin: {
|
|
40
|
-
component: any;
|
|
41
|
-
};
|
|
42
|
-
}>;
|
|
43
|
-
}>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.collection = void 0;
|
|
4
|
-
const fields_1 = require("../fields");
|
|
5
|
-
const extend_fields_1 = require("./extend-fields");
|
|
6
|
-
const collection = (config) => {
|
|
7
|
-
return (0, extend_fields_1.extendFields)(config, {
|
|
8
|
-
id: (0, fields_1.primary)((0, fields_1.field)({ type: (0, fields_1.serial)() })),
|
|
9
|
-
createdAt: (0, fields_1.field)({ type: (0, fields_1.timestamp)() }),
|
|
10
|
-
updatedAt: (0, fields_1.field)({ type: (0, fields_1.timestamp)() }),
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
exports.collection = collection;
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { Field } from "../fields";
|
|
2
|
-
import { Collection } from "./types";
|
|
3
|
-
export declare const extendFields: <const Slug extends string, const Fields extends Record<string, Field>, const NewFields extends Record<string, Field>>(base: Collection<Slug, Fields>, newFields: NewFields) => Collection<Slug, Fields & NewFields>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extendFields = void 0;
|
|
4
|
-
const extendFields = (base, newFields) => {
|
|
5
|
-
return {
|
|
6
|
-
...base,
|
|
7
|
-
fields: {
|
|
8
|
-
...base.fields,
|
|
9
|
-
...newFields,
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
exports.extendFields = extendFields;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './define';
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./define"), exports);
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Field } from "../fields";
|
|
2
|
-
export type CollectionHooks = {
|
|
3
|
-
beforeCreate?: (data: any) => Promise<any>;
|
|
4
|
-
afterCreate?: (data: any) => Promise<any>;
|
|
5
|
-
beforeUpdate?: (data: any) => Promise<any>;
|
|
6
|
-
afterUpdate?: (data: any) => Promise<any>;
|
|
7
|
-
beforeDelete?: (data: any) => Promise<any>;
|
|
8
|
-
afterDelete?: (data: any) => Promise<any>;
|
|
9
|
-
beforeOperation?: (data: any) => Promise<any>;
|
|
10
|
-
afterOperation?: (data: any) => Promise<any>;
|
|
11
|
-
afterError?: (error: Error) => Promise<any>;
|
|
12
|
-
afterSuccess?: (data: any) => Promise<any>;
|
|
13
|
-
};
|
|
14
|
-
export type Collection<Slug extends string = string, Fields extends Record<string, Field> = Record<string, Field>> = {
|
|
15
|
-
slug: Slug;
|
|
16
|
-
name?: string;
|
|
17
|
-
admin?: {
|
|
18
|
-
title?: string;
|
|
19
|
-
group?: string;
|
|
20
|
-
};
|
|
21
|
-
fields: Fields;
|
|
22
|
-
hooks?: CollectionHooks;
|
|
23
|
-
permissions?: {
|
|
24
|
-
create?: (ctx: any) => Promise<boolean>;
|
|
25
|
-
read?: (ctx: any) => Promise<boolean>;
|
|
26
|
-
update?: (ctx: any) => Promise<boolean>;
|
|
27
|
-
delete?: (ctx: any) => Promise<boolean>;
|
|
28
|
-
};
|
|
29
|
-
};
|
package/dist/config/index.d.ts
DELETED
package/dist/config/index.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.defineConfig = void 0;
|
|
7
|
-
const node_postgres_1 = require("drizzle-orm/node-postgres");
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
// Fonction pour charger le schéma généré sans faire planter le build
|
|
10
|
-
const loadGeneratedSchema = () => {
|
|
11
|
-
try {
|
|
12
|
-
// 1. Essai via l'alias Webpack/Turbopack (Client/Server Next.js)
|
|
13
|
-
return require("@deesse/schema");
|
|
14
|
-
}
|
|
15
|
-
catch (e) {
|
|
16
|
-
try {
|
|
17
|
-
// 2. Essai via chemin système (Scripts/Worker)
|
|
18
|
-
return require(path_1.default.join(process.cwd(), ".deesse", "shadow", "schema.ts"));
|
|
19
|
-
}
|
|
20
|
-
catch (e2) {
|
|
21
|
-
// 3. Pas encore généré (Premier boot)
|
|
22
|
-
return {};
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
const defineConfig = (config) => {
|
|
27
|
-
// Charger le schéma dynamiquement
|
|
28
|
-
const schema = loadGeneratedSchema();
|
|
29
|
-
// Initialiser Drizzle avec le schéma
|
|
30
|
-
const db = (0, node_postgres_1.drizzle)(config.databaseUrl, {
|
|
31
|
-
schema,
|
|
32
|
-
// logger: true // Décommentez pour debug
|
|
33
|
-
});
|
|
34
|
-
// Attacher la config brute pour que le Worker puisse la lire via Jiti
|
|
35
|
-
Object.defineProperty(db, '_config', {
|
|
36
|
-
value: config,
|
|
37
|
-
enumerable: false,
|
|
38
|
-
writable: false
|
|
39
|
-
});
|
|
40
|
-
// On retourne "any" ici au niveau du runtime de la lib.
|
|
41
|
-
// La vraie magie se passe dans .deesse/types.d.ts qui surcharge ce type
|
|
42
|
-
// pour l'utilisateur final.
|
|
43
|
-
return db;
|
|
44
|
-
};
|
|
45
|
-
exports.defineConfig = defineConfig;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Collection } from "../collections/types";
|
|
2
|
-
import { Provider } from "../providers/types";
|
|
3
|
-
type Action = 'create' | 'read' | 'update' | 'delete';
|
|
4
|
-
export declare const runOperation: (action: Action, collection: Collection, provider: Provider, payload: {
|
|
5
|
-
id?: string;
|
|
6
|
-
data?: any;
|
|
7
|
-
}) => Promise<any>;
|
|
8
|
-
export {};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runOperation = void 0;
|
|
4
|
-
const runOperation = async (action, collection, provider, payload) => {
|
|
5
|
-
const { hooks } = collection;
|
|
6
|
-
let currentData = payload.data;
|
|
7
|
-
const id = payload.id;
|
|
8
|
-
try {
|
|
9
|
-
// 1. Hook Global: beforeOperation
|
|
10
|
-
if (hooks?.beforeOperation) {
|
|
11
|
-
await hooks.beforeOperation({ action, collection: collection.slug, data: currentData, id });
|
|
12
|
-
}
|
|
13
|
-
// 2. Hook Spécifique: before[Action]
|
|
14
|
-
// Note: TypeScript peut être strict ici, on simplifie pour la demo
|
|
15
|
-
if (action === 'create' && hooks?.beforeCreate)
|
|
16
|
-
currentData = await hooks.beforeCreate(currentData);
|
|
17
|
-
if (action === 'update' && hooks?.beforeUpdate)
|
|
18
|
-
currentData = await hooks.beforeUpdate(currentData);
|
|
19
|
-
if (action === 'delete' && hooks?.beforeDelete)
|
|
20
|
-
await hooks.beforeDelete({ id });
|
|
21
|
-
// 3. APPEL AU PROVIDER (Le vrai travail DB)
|
|
22
|
-
let result;
|
|
23
|
-
switch (action) {
|
|
24
|
-
case 'create':
|
|
25
|
-
result = await provider.create(collection.slug, currentData);
|
|
26
|
-
break;
|
|
27
|
-
case 'read':
|
|
28
|
-
if (!id)
|
|
29
|
-
throw new Error("ID required for read");
|
|
30
|
-
result = await provider.read(collection.slug, id);
|
|
31
|
-
break;
|
|
32
|
-
case 'update':
|
|
33
|
-
if (!id)
|
|
34
|
-
throw new Error("ID required for update");
|
|
35
|
-
result = await provider.update(collection.slug, id, currentData);
|
|
36
|
-
break;
|
|
37
|
-
case 'delete':
|
|
38
|
-
if (!id)
|
|
39
|
-
throw new Error("ID required for delete");
|
|
40
|
-
await provider.delete(collection.slug, id);
|
|
41
|
-
result = { success: true, id };
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
// 4. Hook Spécifique: after[Action]
|
|
45
|
-
if (action === 'create' && hooks?.afterCreate)
|
|
46
|
-
result = await hooks.afterCreate(result);
|
|
47
|
-
if (action === 'update' && hooks?.afterUpdate)
|
|
48
|
-
result = await hooks.afterUpdate(result);
|
|
49
|
-
if (action === 'delete' && hooks?.afterDelete)
|
|
50
|
-
result = await hooks.afterDelete(result);
|
|
51
|
-
// 5. Hook Global: afterOperation
|
|
52
|
-
if (hooks?.afterOperation) {
|
|
53
|
-
await hooks.afterOperation({ action, result });
|
|
54
|
-
}
|
|
55
|
-
// 6. Hook Global: afterSuccess (spécifique à ta liste)
|
|
56
|
-
if (hooks?.afterSuccess) {
|
|
57
|
-
await hooks.afterSuccess(result);
|
|
58
|
-
}
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
// Gestion des erreurs via les hooks
|
|
63
|
-
if (hooks?.afterError) {
|
|
64
|
-
// Le hook peut transformer l'erreur ou la logger
|
|
65
|
-
await hooks.afterError(error);
|
|
66
|
-
}
|
|
67
|
-
throw error; // On relance l'erreur pour que l'appelant sache que ça a échoué
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
exports.runOperation = runOperation;
|
package/dist/config/types.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Collection } from "../collections/types";
|
|
2
|
-
import { CollectionsCrud } from "../database/types";
|
|
3
|
-
import { Field, FieldTypeFinal } from "../fields";
|
|
4
|
-
import { Plugin } from "../plugins/types";
|
|
5
|
-
import { UnionToIntersection } from "../utils/union-intersection";
|
|
6
|
-
export type Config = {
|
|
7
|
-
databaseUrl: string;
|
|
8
|
-
readonly collections: Collection[];
|
|
9
|
-
plugins?: Plugin[];
|
|
10
|
-
};
|
|
11
|
-
export type DbFromConfig<C extends Config> = UnionToIntersection<CollectionsCrud<C["collections"][number]>>;
|
|
12
|
-
export type InferSchema<F extends Record<string, Field>> = {
|
|
13
|
-
[K in keyof F]: F[K] extends Field<infer FT> ? FT extends FieldTypeFinal<any, infer TVal> ? TVal : never : never;
|
|
14
|
-
};
|
package/dist/config/types.js
DELETED
package/dist/database/types.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Collection } from "../collections/types";
|
|
2
|
-
import { InferSchema } from "../fields/types";
|
|
3
|
-
export type CollectionsCrud<C extends Collection> = {
|
|
4
|
-
[K in C["slug"]]: {
|
|
5
|
-
create: (data: InferSchema<C["fields"]>) => Promise<any>;
|
|
6
|
-
read: (id: string) => Promise<any>;
|
|
7
|
-
update: (id: string, data: Partial<InferSchema<C["fields"]>>) => Promise<any>;
|
|
8
|
-
delete: (id: string) => Promise<void>;
|
|
9
|
-
};
|
|
10
|
-
};
|
package/dist/database/types.js
DELETED