Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pull-exclude-obsessiondb-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chkit/plugin-pull": patch
---

`chkit pull` no longer emits ObsessionDB product-metadata tables (`metadata_folder`, `metadata_table_folder`, `metadata_table_tag`) into generated schema files. These are ObsessionDB internals provisioned inside customer databases, not part of the user's schema — emitting them polluted the schema and caused drift against tables the user does not own. They are now excluded before rendering and are not counted as skipped/unsupported objects.
64 changes: 64 additions & 0 deletions packages/plugin-pull/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,70 @@ describe('@chkit/plugin-pull schema command', () => {
expect(payload.content).toContain('default: "fn:\'\'"')
})

test('excludes ObsessionDB metadata tables from pulled schema output', async () => {
const introspectedTable = (name: string) => ({
database: 'app',
name,
engine: 'MergeTree()',
primaryKey: '(id)',
orderBy: '(id)',
columns: [{ name: 'id', type: 'UInt64' }],
settings: {},
indexes: [],
projections: [],
})
const plugin = createPullPlugin({
databases: ['app'],
introspect: async () => [
introspectedTable('events'),
introspectedTable('metadata_folder'),
introspectedTable('metadata_table_folder'),
introspectedTable('metadata_table_tag'),
],
})

const command = plugin.commands[0]
if (!command) throw new Error('missing command')

const logs: unknown[] = []
const code = await command.run({
args: [],
flags: { '--dryrun': true },
jsonMode: true,
options: PullSchema.parse({ databases: ['app'] }),
rawOptions: { databases: ['app'] },
configPath: '/tmp/clickhouse.config.ts',
config: {
schema: ['./schema.ts'],
outDir: './chkit',
migrationsDir: './chkit/migrations',
metaDir: './chkit/meta',
plugins: [],
check: { failOnPending: true, failOnChecksumMismatch: true, failOnDrift: true },
safety: { allowDestructive: false },
clickhouse: {
url: 'http://localhost:8123',
username: 'default',
password: '',
database: 'default',
secure: false,
},
},
print(value) {
logs.push(value)
},
})

expect(code).toBe(0)
const payload = logs[0] as { definitionCount: number; tableCount: number; content: string }
expect(payload.definitionCount).toBe(1)
expect(payload.tableCount).toBe(1)
expect(payload.content).toContain('const app_events = table({')
expect(payload.content).not.toContain('metadata_folder')
expect(payload.content).not.toContain('metadata_table_folder')
expect(payload.content).not.toContain('metadata_table_tag')
})

test('supports introspected view and materialized_view objects', async () => {
const plugin = createPullPlugin({
databases: ['app'],
Expand Down
35 changes: 28 additions & 7 deletions packages/plugin-pull/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,24 @@

// ───── Internal helpers ─────

// ObsessionDB provisions these product-metadata tables inside customer
// databases. They are ObsessionDB internals, not part of the user's schema, so
// pull must neither emit them nor count them as skipped/unsupported (#126).
const OBSESSIONDB_METADATA_TABLES = new Set([
'metadata_folder',
'metadata_table_folder',
'metadata_table_tag',
])

function isObsessionDbMetadataTable(object: { kind?: string; name: string }): boolean {
// An introspected object is a table when it says so or omits `kind` entirely,
// mirroring mapIntrospectedObjectToDefinition — a custom introspector returns
// bare table objects without a `kind` field.
const isTable = object.kind == null || object.kind === 'table'
return isTable && OBSESSIONDB_METADATA_TABLES.has(object.name)
}

async function pullSchema(input: {

Check warning on line 265 in packages/plugin-pull/src/index.ts

View workflow job for this annotation

GitHub Actions / verify

High CRAP score (moderate)

Function 'pullSchema' has a CRAP score of 43.1 (threshold: 30.0). • Severity: moderate • Cyclomatic: 12 • Cognitive: 12 • CRAP: 43.1 (threshold: 30.0) • Lines: 60 CRAP combines complexity with coverage: high CRAP means changes here carry high risk. Consider adding tests, simplifying the function, or both.
config: ResolvedChxConfig
executor?: ClickHouseExecutor | null
options: PullOptions & { introspect?: PullIntrospector }
Expand Down Expand Up @@ -274,18 +291,22 @@
let selectedDatabases = input.options.databases

if (db && (!customIntrospector || selectedDatabases.length === 0)) {
objects = await db.listSchemaObjects()
objects = (await db.listSchemaObjects()).filter(
(item) => !isObsessionDbMetadataTable(item)
)
if (selectedDatabases.length === 0) {
selectedDatabases = [...new Set(objects.map((item) => item.database))].sort()
}
}

const introspected = customIntrospector
? await customIntrospector({
config: input.config.clickhouse as NonNullable<ResolvedChxConfig['clickhouse']>,
databases: selectedDatabases,
})
: await introspectWithExecutor(db as ClickHouseExecutor, selectedDatabases)
const introspected = (
customIntrospector
? await customIntrospector({
config: input.config.clickhouse as NonNullable<ResolvedChxConfig['clickhouse']>,
databases: selectedDatabases,
})
: await introspectWithExecutor(db as ClickHouseExecutor, selectedDatabases)
).filter((object) => !isObsessionDbMetadataTable(object))

const definitions = canonicalizeDefinitions(introspected.map(mapIntrospectedObjectToDefinition))
const content = renderSchemaFile(definitions)
Expand Down
Loading