Skip to content

Instantly share code, notes, and snippets.

@symbioquine
Created January 31, 2026 14:46
Show Gist options
  • Select an option

  • Save symbioquine/7a67edccd32ea634cc5bf0597f9c7f31 to your computer and use it in GitHub Desktop.

Select an option

Save symbioquine/7a67edccd32ea634cc5bf0597f9c7f31 to your computer and use it in GitHub Desktop.
Finds orphaned quantities in farmOS - not referenced by any current log revision
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"kernelspec": {
"name": "python",
"display_name": "Python (Pyodide)",
"language": "python"
},
"language_info": {
"codemirror_mode": {
"name": "python",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8"
}
},
"nbformat_minor": 5,
"nbformat": 4,
"cells": [
{
"id": "952a6f9d-30db-4a1c-898e-f098c2b58d54",
"cell_type": "code",
"source": "from pyodide.http import pyfetch\nfrom js import location\nimport json\n\nasync def get_all_entities(base_url):\n next_page = base_url\n while next_page is not None:\n resp = await pyfetch(next_page, method='GET')\n\n data = await resp.json()\n\n for entity in data.get('data', []):\n yield entity\n\n next_page = data.get('links', {}).get('next', {}).get('href', None)\n",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": 1
},
{
"id": "3132a1de-2720-4d00-ba73-7903dc8b0666",
"cell_type": "code",
"source": "all_quantity_types = [q['attributes']['drupal_internal__id'] async for q in get_all_entities(location.origin + '/api/quantity_type/quantity_type')]\n\nprint(all_quantity_types)",
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": "['material', 'standard']\n"
}
],
"execution_count": 2
},
{
"id": "32a3b012-2503-4962-a977-f5e9ae9eaaae",
"cell_type": "code",
"source": "all_quantity_ids = {q['id'] for quantity_type in all_quantity_types async for q in get_all_entities(f'{location.origin}/api/quantity/{quantity_type}?fields[quantity--{quantity_type}]=id&sort=drupal_internal__id')}\n\nlen(all_quantity_ids)",
"metadata": {
"trusted": true
},
"outputs": [
{
"execution_count": 14,
"output_type": "execute_result",
"data": {
"text/plain": "5538"
},
"metadata": {}
}
],
"execution_count": 14
},
{
"id": "4034aa2c-0952-4b61-b17c-f88b43e4fe57",
"cell_type": "code",
"source": "all_log_types = [q['attributes']['drupal_internal__id'] async for q in get_all_entities(location.origin + '/api/log_type/log_type')]\n\nprint(all_log_types)",
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": "['activity', 'birth', 'harvest', 'input', 'maintenance', 'observation', 'seeding']\n"
}
],
"execution_count": 5
},
{
"id": "62b7d49e-a1d7-412c-ab56-54c47510c0a2",
"cell_type": "code",
"source": "# Kind of a weird function: iterate through the pages, but yield the included entities\nasync def get_all_entities_includes(base_url):\n next_page = base_url\n while next_page is not None:\n resp = await pyfetch(next_page, method='GET')\n\n data = await resp.json()\n\n for entity in data.get('included', []):\n yield entity\n\n next_page = data.get('links', {}).get('next', {}).get('href', None)\n\nquantity_fields_query_part = '&'.join([f'fields[quantity--{quantity_type}]=id' for quantity_type in all_quantity_types])\n\nlogs_with_quantities_filter = 'filter[a][condition][path]=quantity.id&filter[a][condition][operator]=IS NOT NULL'\n\nbase_query = lambda log_type: f'{location.origin}/api/log/{log_type}?{logs_with_quantities_filter}&sort=drupal_internal__id&fields[log--{log_type}]=&include=quantity&{quantity_fields_query_part}'\n\nall_referenced_quantity_ids = {q['id'] for log_type in all_log_types async for q in get_all_entities_includes(base_query(log_type))}\n\nlen(all_referenced_quantity_ids)",
"metadata": {
"trusted": true
},
"outputs": [
{
"execution_count": 10,
"output_type": "execute_result",
"data": {
"text/plain": "5514"
},
"metadata": {}
}
],
"execution_count": 10
},
{
"id": "91763140-6784-49c5-991e-d4e8911488d7",
"cell_type": "code",
"source": "len(all_quantity_ids - all_referenced_quantity_ids)",
"metadata": {
"trusted": true
},
"outputs": [
{
"execution_count": 15,
"output_type": "execute_result",
"data": {
"text/plain": "24"
},
"metadata": {}
}
],
"execution_count": 15
},
{
"id": "89c882f9-313d-4e87-885e-35241bbef6c9",
"cell_type": "code",
"source": "len(all_referenced_quantity_ids - all_quantity_ids)",
"metadata": {
"trusted": true
},
"outputs": [
{
"execution_count": 16,
"output_type": "execute_result",
"data": {
"text/plain": "0"
},
"metadata": {}
}
],
"execution_count": 16
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment