{"version":3,"file":"migration-factories-BEEn4aIy.mjs","names":[],"sources":["../src/core/migration-factories.ts"],"sourcesContent":["import type {\n  MongoDataTransformCheck,\n  MongoDataTransformOperation,\n  MongoFilterExpr,\n  MongoIndexKey,\n} from '@prisma-next/mongo-query-ast/control';\nimport {\n  buildIndexOpId,\n  CollModCommand,\n  type CollModOptions,\n  type CreateCollectionOptions,\n  type CreateIndexOptions,\n  DropCollectionCommand,\n  DropIndexCommand,\n  defaultMongoIndexName,\n  keysToKeySpec,\n  ListCollectionsCommand,\n  ListIndexesCommand,\n  MongoAndExpr,\n  MongoExistsExpr,\n  MongoFieldFilter,\n  type MongoMigrationPlanOperation,\n} from '@prisma-next/mongo-query-ast/control';\nimport type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';\nimport { createFieldAccessor } from '@prisma-next/mongo-query-builder';\nimport { collection } from '@prisma-next/mongo-query-builder/contract-free';\nimport type { MongoValue } from '@prisma-next/mongo-value';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { CollModMeta } from './op-factory-call';\n\ntype StringField = { readonly codecId: 'mongo/string@1'; readonly nullable: false };\ntype BoolField = { readonly codecId: 'mongo/bool@1'; readonly nullable: false };\ntype DocField = { readonly codecId: 'mongo/document@1'; readonly nullable: false };\n\ntype IndexInfoDocShape = {\n  readonly key: DocField;\n  readonly unique: BoolField;\n  readonly name: StringField;\n};\n\ntype CollectionInfoDocShape = {\n  readonly name: StringField;\n};\n\ninterface Buildable {\n  build(): MongoQueryPlan;\n}\n\nfunction isBuildable(value: unknown): value is Buildable {\n  return (\n    typeof value === 'object' &&\n    value !== null &&\n    'build' in value &&\n    typeof (value as { build: unknown }).build === 'function'\n  );\n}\n\nfunction resolveQuery(value: MongoQueryPlan | Buildable): MongoQueryPlan {\n  return isBuildable(value) ? value.build() : value;\n}\n\n// Every MongoDB document carries `_id`, so `exists('_id')` is equivalent to\n// \"match all\". The filter AST has no identity/always-true expression.\nconst MATCH_ALL_FILTER: MongoFilterExpr = MongoExistsExpr.exists('_id');\n\nexport function dataTransform(\n  name: string,\n  options: {\n    /**\n     * Optional opt-in routing identity. Presence opts the transform into\n     * invariant-aware routing; absence means it is path-dependent and\n     * not referenceable from refs.\n     */\n    invariantId?: string;\n    check?: {\n      source: () => MongoQueryPlan | Buildable;\n      filter?: MongoFilterExpr;\n      expect?: 'exists' | 'notExists';\n      description?: string;\n    };\n    run: () => MongoQueryPlan | Buildable;\n  },\n): MongoDataTransformOperation {\n  let precheck: readonly MongoDataTransformCheck[] = [];\n  let postcheck: readonly MongoDataTransformCheck[] = [];\n\n  if (options.check) {\n    const source = resolveQuery(options.check.source());\n    const filter = options.check.filter ?? MATCH_ALL_FILTER;\n    const description = options.check.description ?? `Check for data transform: ${name}`;\n    const precheckExpect = options.check.expect ?? 'exists';\n    const postcheckExpect: 'exists' | 'notExists' =\n      precheckExpect === 'exists' ? 'notExists' : 'exists';\n\n    precheck = [{ description, source, filter, expect: precheckExpect }];\n    postcheck = [{ description, source, filter, expect: postcheckExpect }];\n  }\n\n  const run: MongoQueryPlan[] = [resolveQuery(options.run())];\n\n  return {\n    id: `data_transform.${name}`,\n    label: `Data transform: ${name}`,\n    operationClass: 'data',\n    name,\n    ...ifDefined('invariantId', options.invariantId),\n    precheck,\n    run,\n    postcheck,\n  };\n}\n\nfunction formatKeys(keys: ReadonlyArray<MongoIndexKey>): string {\n  return keys.map((k) => `${k.field}:${k.direction}`).join(', ');\n}\n\nfunction isTextIndex(keys: ReadonlyArray<MongoIndexKey>): boolean {\n  return keys.some((k) => k.direction === 'text');\n}\n\nfunction keyFilter(keys: ReadonlyArray<MongoIndexKey>) {\n  const f = createFieldAccessor<IndexInfoDocShape>();\n  return isTextIndex(keys)\n    ? f.rawPath('key._fts').eq('text')\n    : f.key.eq(\n        blindCast<\n          MongoValue,\n          'keysToKeySpec returns a plain BSON object used as a MongoValue equality target'\n        >(keysToKeySpec(keys)),\n      );\n}\n\nexport function createIndex(\n  collectionName: string,\n  keys: ReadonlyArray<MongoIndexKey>,\n  options?: CreateIndexOptions,\n): MongoMigrationPlanOperation {\n  const name = defaultMongoIndexName(keys);\n  const f = createFieldAccessor<IndexInfoDocShape>();\n  const filter = keyFilter(keys);\n  const fullFilter = options?.unique ? filter.and(f.unique.eq(true)) : filter;\n\n  return {\n    id: buildIndexOpId('create', collectionName, keys),\n    label: `Create index on ${collectionName} (${formatKeys(keys)})`,\n    operationClass: 'additive',\n    precheck: [\n      {\n        description: `index does not already exist on ${collectionName}`,\n        source: new ListIndexesCommand(collectionName),\n        filter,\n        expect: 'notExists',\n      },\n    ],\n    execute: [\n      {\n        description: `create index on ${collectionName}`,\n        command: collection(collectionName).createIndex(keys, {\n          ...options,\n          name,\n        }),\n      },\n    ],\n    postcheck: [\n      {\n        description: `index exists on ${collectionName}`,\n        source: new ListIndexesCommand(collectionName),\n        filter: fullFilter,\n        expect: 'exists',\n      },\n    ],\n  };\n}\n\nexport function dropIndex(\n  collectionName: string,\n  keys: ReadonlyArray<MongoIndexKey>,\n): MongoMigrationPlanOperation {\n  const indexName = defaultMongoIndexName(keys);\n  const filter = keyFilter(keys);\n\n  return {\n    id: buildIndexOpId('drop', collectionName, keys),\n    label: `Drop index on ${collectionName} (${formatKeys(keys)})`,\n    operationClass: 'destructive',\n    precheck: [\n      {\n        description: `index exists on ${collectionName}`,\n        source: new ListIndexesCommand(collectionName),\n        filter,\n        expect: 'exists',\n      },\n    ],\n    execute: [\n      {\n        description: `drop index on ${collectionName}`,\n        command: new DropIndexCommand(collectionName, indexName),\n      },\n    ],\n    postcheck: [\n      {\n        description: `index no longer exists on ${collectionName}`,\n        source: new ListIndexesCommand(collectionName),\n        filter,\n        expect: 'notExists',\n      },\n    ],\n  };\n}\n\nexport function createCollection(\n  collectionName: string,\n  options?: CreateCollectionOptions,\n): MongoMigrationPlanOperation {\n  const f = createFieldAccessor<CollectionInfoDocShape>();\n\n  return {\n    id: `collection.${collectionName}.create`,\n    label: `Create collection ${collectionName}`,\n    operationClass: 'additive',\n    precheck: [\n      {\n        description: `collection ${collectionName} does not exist`,\n        source: new ListCollectionsCommand(),\n        filter: f.name.eq(collectionName),\n        expect: 'notExists',\n      },\n    ],\n    execute: [\n      {\n        description: `create collection ${collectionName}`,\n        command: collection(collectionName).createCollection(options),\n      },\n    ],\n    postcheck: [],\n  };\n}\n\nexport function dropCollection(collectionName: string): MongoMigrationPlanOperation {\n  return {\n    id: `collection.${collectionName}.drop`,\n    label: `Drop collection ${collectionName}`,\n    operationClass: 'destructive',\n    precheck: [],\n    execute: [\n      {\n        description: `drop collection ${collectionName}`,\n        command: new DropCollectionCommand(collectionName),\n      },\n    ],\n    postcheck: [],\n  };\n}\n\nexport function setValidation(\n  collectionName: string,\n  schema: Record<string, unknown>,\n  options?: { validationLevel?: 'strict' | 'moderate'; validationAction?: 'error' | 'warn' },\n): MongoMigrationPlanOperation {\n  return {\n    id: `collection.${collectionName}.setValidation`,\n    label: `Set validation on ${collectionName}`,\n    operationClass: 'destructive',\n    precheck: [],\n    execute: [\n      {\n        description: `set validation on ${collectionName}`,\n        command: new CollModCommand(collectionName, {\n          validator: { $jsonSchema: schema },\n          ...ifDefined('validationLevel', options?.validationLevel),\n          ...ifDefined('validationAction', options?.validationAction),\n        }),\n      },\n    ],\n    postcheck: [],\n  };\n}\n\nexport function collMod(\n  collectionName: string,\n  options: CollModOptions,\n  meta?: CollModMeta,\n): MongoMigrationPlanOperation {\n  const hasValidator = options.validator != null && Object.keys(options.validator).length > 0;\n\n  return {\n    id: meta?.id ?? `collection.${collectionName}.collMod`,\n    label: meta?.label ?? `Modify collection ${collectionName}`,\n    operationClass: meta?.operationClass ?? 'destructive',\n    precheck:\n      options.validator != null\n        ? [\n            {\n              description: `collection ${collectionName} exists`,\n              source: new ListCollectionsCommand(),\n              filter: MongoFieldFilter.eq('name', collectionName),\n              expect: 'exists' as const,\n            },\n          ]\n        : [],\n    execute: [\n      {\n        description: `modify ${collectionName}`,\n        command: new CollModCommand(collectionName, options),\n      },\n    ],\n    postcheck: hasValidator\n      ? [\n          {\n            description: `validator applied on ${collectionName}`,\n            source: new ListCollectionsCommand(),\n            filter: MongoAndExpr.of([\n              MongoFieldFilter.eq('name', collectionName),\n              ...(options.validationLevel\n                ? [MongoFieldFilter.eq('options.validationLevel', options.validationLevel)]\n                : []),\n              ...(options.validationAction\n                ? [MongoFieldFilter.eq('options.validationAction', options.validationAction)]\n                : []),\n              // Include the $jsonSchema body so the idempotency probe only skips when the\n              // live validator body genuinely already equals the target — not merely when\n              // level/action happen to be unchanged (which was the silent-skip bug for widen ops).\n              // MongoFieldFilter.eq compares with order-sensitive deepEqual, not canonicalize.\n              // That is safe here because MongoDB preserves BSON key order when round-tripping\n              // the $jsonSchema through listCollections (confirmed by the MMS integration test),\n              // so a matching live validator compares equal. The only consequence of skipping\n              // canonicalization is a safe false-negative on the skip: a validator installed\n              // out-of-band with a different key order simply re-runs the collMod harmlessly.\n              // The cast is safe: CollModOptions.validator is Record<string,unknown>, and its\n              // $jsonSchema value is always a plain BSON object (MongoDocument at runtime).\n              ...(options.validator?.['$jsonSchema'] !== undefined\n                ? [\n                    MongoFieldFilter.eq(\n                      'options.validator.$jsonSchema',\n                      blindCast<\n                        MongoValue,\n                        'options.validator.$jsonSchema is a plain BSON object — the factory only populates this from a MongoSchemaValidator.jsonSchema record, which is a MongoDocument at runtime'\n                      >(options.validator?.['$jsonSchema']),\n                    ),\n                  ]\n                : []),\n            ]),\n            expect: 'exists' as const,\n          },\n        ]\n      : [],\n  };\n}\n\nexport function validatedCollection(\n  name: string,\n  schema: Record<string, unknown>,\n  indexes: ReadonlyArray<{ keys: MongoIndexKey[]; unique?: boolean }>,\n): MongoMigrationPlanOperation[] {\n  return [\n    createCollection(name, {\n      validator: { $jsonSchema: schema },\n      validationLevel: 'strict',\n      validationAction: 'error',\n    }),\n    ...indexes.map((idx) =>\n      createIndex(name, idx.keys, idx.unique !== undefined ? { unique: idx.unique } : undefined),\n    ),\n  ];\n}\n"],"mappings":"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"}