Repository: directus/directus
File: api/src/telemetry/utils/get-extension-count.ts (TypeScript)

Code before:
	const counts: ExtensionCount = {
		activeTotal: 0,
		activeBundles: 0,
	};

	const result = <{ count: number | string }[]>(
		await db.count('*', { as: 'count' }).from('directus_extensions').where('enabled', '=', true)
	);

	const bundleResult = <{ count: number | string }[]>(
		await db
			.count('*', { as: 'count' })
			.from('directus_extensions')
			.whereIn('id', db.distinct('bundle').from('directus_extensions'))
			.andWhere('enabled', '=', true)
	);

	if (result[0]?.count) {
		counts.activeTotal = Number(result[0].count);
	}

	if (bundleResult[0]?.count) {
		counts.activeBundles = Number(bundleResult[0].count);
	}

	return counts;
};


Review comment (bug):
Tbh I find it unintuitive to count active bundles because a bundle can be active while all of its children are disabled but we dont care about bundle parents either way. This means:

1. `activeTotal` can be considered _technically_ correct, as in it shows rows which are enabled, but with our definition that bundle-parents are not to be considered for the count, its semantically wrong and could lead to confusion down the line when someone uses the count for calculating something.
2. Currently we only use the `activeBundles` as a crutch to massage `activeTotal` into our correct count definition **outside(!)** of this function. If we stick to counting bundle-parents, we should subtract them here to avoid misunderstandings in the future. Right now if somebody uses `activeTotal` outside this function without subtracting the bundles, its wrong. Its too easy to forget the subtraction.

With the following you actually return all extensions excluding bundle-parents:

```sql
SELECT *
FROM directus_extensions
WHERE id NOT IN (
        SELECT DISTINCT d1.id 
        FROM directus_extensions as d1
        INNER JOIN directus_extensions as d2 ON d1.id = d2.bundle
);
```

Or aggregate them in a single query:

```sql
SELECT enabled, COUNT(enabled)
FROM directus_extensions
where id NOT IN (
        SELECT DISTINCT d1.id 
        FROM directus_extensions as d1
        INNER JOIN directus_extensions as d2 ON d1.id = d2.bundle
) GROUP BY enabled;
```

Which gives you a neat summary for both states while still excluding bundle parents:

```
enabled  COUNT(enabled)
-------  --------------
0        2             
1        3             
```

If we stick to only transmitting enabled extensions we can do this to get the count directly:

```sql
SELECT COUNT(*)
FROM directus_extensions
WHERE enabled = true AND id NOT IN (
        SELECT DISTINCT d1.id 
        FROM directus_extensions as d1
        INNER JOIN directus_extensions as d2 ON d1.id = d2.bundle
);
```

Code after:
import { type Knex } from 'knex';
import { ExtensionsService } from '../../services/extensions.js';
import { getSchema } from '../../utils/get-schema.js';

export interface ExtensionCount {
	/**
	 * Total count of enabled extensions excluding Bundle-Parents,
	 * meaning a Bundle extensions with one extension inside of it counts as one.
	 */
	totalEnabled: number;
}

export const getExtensionCount = async (db: Knex): Promise<ExtensionCount> => {
	const extensionsService = new ExtensionsService({
		knex: db,
		schema: await getSchema({ database: db }),
	});

	const extensions = await extensionsService.readAll();

	let totalEnabled = 0;

	for (const extension of extensions) {
		if (extension.meta.enabled && extension.schema && extension.schema.type !== 'bundle') {
			totalEnabled++;
		}
	}

	return {
		totalEnabled,
	};
};