auto-claude: 4.3 - Add save_audit_result method with ON CONFLICT DO UPDATE
- Enhanced save_audit_result method with complete column coverage - Added missing columns to idempotent upsert query: - broken_links_count (for future link checking) - viewport_configured (derived from meta viewport tag) - is_mobile_friendly (derived from viewport content) - has_hreflang (for international SEO detection) - All 45+ SEO columns now properly mapped for database upserts - ON CONFLICT (company_id) DO UPDATE ensures idempotent operations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c8eb0829d9
commit
c24c545cfe
@ -501,6 +501,7 @@ class SEOAuditor:
|
|||||||
ps_scores = pagespeed.get('scores', {}) if pagespeed else {}
|
ps_scores = pagespeed.get('scores', {}) if pagespeed else {}
|
||||||
|
|
||||||
# Upsert query for company_website_analysis
|
# Upsert query for company_website_analysis
|
||||||
|
# Uses ON CONFLICT DO UPDATE for idempotent upserts
|
||||||
upsert_query = text("""
|
upsert_query = text("""
|
||||||
INSERT INTO company_website_analysis (
|
INSERT INTO company_website_analysis (
|
||||||
company_id, analyzed_at, website_url, final_url,
|
company_id, analyzed_at, website_url, final_url,
|
||||||
@ -515,12 +516,13 @@ class SEOAuditor:
|
|||||||
meta_title, meta_description, meta_keywords,
|
meta_title, meta_description, meta_keywords,
|
||||||
h1_count, h2_count, h3_count, h1_text,
|
h1_count, h2_count, h3_count, h1_text,
|
||||||
total_images, images_without_alt, images_with_alt,
|
total_images, images_without_alt, images_with_alt,
|
||||||
internal_links_count, external_links_count,
|
internal_links_count, external_links_count, broken_links_count,
|
||||||
has_structured_data, structured_data_types, structured_data_json,
|
has_structured_data, structured_data_types, structured_data_json,
|
||||||
|
|
||||||
-- Technical SEO
|
-- Technical SEO
|
||||||
has_canonical, canonical_url, is_indexable, noindex_reason,
|
has_canonical, canonical_url, is_indexable, noindex_reason,
|
||||||
has_sitemap, has_robots_txt,
|
has_sitemap, has_robots_txt,
|
||||||
|
viewport_configured, is_mobile_friendly,
|
||||||
|
|
||||||
-- Core Web Vitals
|
-- Core Web Vitals
|
||||||
largest_contentful_paint_ms, first_input_delay_ms, cumulative_layout_shift,
|
largest_contentful_paint_ms, first_input_delay_ms, cumulative_layout_shift,
|
||||||
@ -529,8 +531,8 @@ class SEOAuditor:
|
|||||||
has_og_tags, og_title, og_description, og_image,
|
has_og_tags, og_title, og_description, og_image,
|
||||||
has_twitter_cards,
|
has_twitter_cards,
|
||||||
|
|
||||||
-- Language
|
-- Language & International
|
||||||
html_lang,
|
html_lang, has_hreflang,
|
||||||
|
|
||||||
-- Word count
|
-- Word count
|
||||||
word_count_homepage,
|
word_count_homepage,
|
||||||
@ -549,18 +551,19 @@ class SEOAuditor:
|
|||||||
:meta_title, :meta_description, :meta_keywords,
|
:meta_title, :meta_description, :meta_keywords,
|
||||||
:h1_count, :h2_count, :h3_count, :h1_text,
|
:h1_count, :h2_count, :h3_count, :h1_text,
|
||||||
:total_images, :images_without_alt, :images_with_alt,
|
:total_images, :images_without_alt, :images_with_alt,
|
||||||
:internal_links_count, :external_links_count,
|
:internal_links_count, :external_links_count, :broken_links_count,
|
||||||
:has_structured_data, :structured_data_types, :structured_data_json,
|
:has_structured_data, :structured_data_types, :structured_data_json,
|
||||||
|
|
||||||
:has_canonical, :canonical_url, :is_indexable, :noindex_reason,
|
:has_canonical, :canonical_url, :is_indexable, :noindex_reason,
|
||||||
:has_sitemap, :has_robots_txt,
|
:has_sitemap, :has_robots_txt,
|
||||||
|
:viewport_configured, :is_mobile_friendly,
|
||||||
|
|
||||||
:largest_contentful_paint_ms, :first_input_delay_ms, :cumulative_layout_shift,
|
:largest_contentful_paint_ms, :first_input_delay_ms, :cumulative_layout_shift,
|
||||||
|
|
||||||
:has_og_tags, :og_title, :og_description, :og_image,
|
:has_og_tags, :og_title, :og_description, :og_image,
|
||||||
:has_twitter_cards,
|
:has_twitter_cards,
|
||||||
|
|
||||||
:html_lang,
|
:html_lang, :has_hreflang,
|
||||||
|
|
||||||
:word_count_homepage,
|
:word_count_homepage,
|
||||||
|
|
||||||
@ -592,6 +595,7 @@ class SEOAuditor:
|
|||||||
images_with_alt = EXCLUDED.images_with_alt,
|
images_with_alt = EXCLUDED.images_with_alt,
|
||||||
internal_links_count = EXCLUDED.internal_links_count,
|
internal_links_count = EXCLUDED.internal_links_count,
|
||||||
external_links_count = EXCLUDED.external_links_count,
|
external_links_count = EXCLUDED.external_links_count,
|
||||||
|
broken_links_count = EXCLUDED.broken_links_count,
|
||||||
has_structured_data = EXCLUDED.has_structured_data,
|
has_structured_data = EXCLUDED.has_structured_data,
|
||||||
structured_data_types = EXCLUDED.structured_data_types,
|
structured_data_types = EXCLUDED.structured_data_types,
|
||||||
structured_data_json = EXCLUDED.structured_data_json,
|
structured_data_json = EXCLUDED.structured_data_json,
|
||||||
@ -602,6 +606,8 @@ class SEOAuditor:
|
|||||||
noindex_reason = EXCLUDED.noindex_reason,
|
noindex_reason = EXCLUDED.noindex_reason,
|
||||||
has_sitemap = EXCLUDED.has_sitemap,
|
has_sitemap = EXCLUDED.has_sitemap,
|
||||||
has_robots_txt = EXCLUDED.has_robots_txt,
|
has_robots_txt = EXCLUDED.has_robots_txt,
|
||||||
|
viewport_configured = EXCLUDED.viewport_configured,
|
||||||
|
is_mobile_friendly = EXCLUDED.is_mobile_friendly,
|
||||||
|
|
||||||
largest_contentful_paint_ms = EXCLUDED.largest_contentful_paint_ms,
|
largest_contentful_paint_ms = EXCLUDED.largest_contentful_paint_ms,
|
||||||
first_input_delay_ms = EXCLUDED.first_input_delay_ms,
|
first_input_delay_ms = EXCLUDED.first_input_delay_ms,
|
||||||
@ -614,6 +620,7 @@ class SEOAuditor:
|
|||||||
has_twitter_cards = EXCLUDED.has_twitter_cards,
|
has_twitter_cards = EXCLUDED.has_twitter_cards,
|
||||||
|
|
||||||
html_lang = EXCLUDED.html_lang,
|
html_lang = EXCLUDED.html_lang,
|
||||||
|
has_hreflang = EXCLUDED.has_hreflang,
|
||||||
|
|
||||||
word_count_homepage = EXCLUDED.word_count_homepage,
|
word_count_homepage = EXCLUDED.word_count_homepage,
|
||||||
|
|
||||||
@ -665,6 +672,7 @@ class SEOAuditor:
|
|||||||
'images_with_alt': images.get('images_with_alt'),
|
'images_with_alt': images.get('images_with_alt'),
|
||||||
'internal_links_count': links.get('internal_links'),
|
'internal_links_count': links.get('internal_links'),
|
||||||
'external_links_count': links.get('external_links'),
|
'external_links_count': links.get('external_links'),
|
||||||
|
'broken_links_count': links.get('broken_links'), # May be None if not checked
|
||||||
'has_structured_data': structured_data.get('has_structured_data', False),
|
'has_structured_data': structured_data.get('has_structured_data', False),
|
||||||
'structured_data_types': structured_data.get('all_types', []),
|
'structured_data_types': structured_data.get('all_types', []),
|
||||||
'structured_data_json': json.dumps(structured_data.get('json_ld_data', [])) if structured_data.get('json_ld_data') else None,
|
'structured_data_json': json.dumps(structured_data.get('json_ld_data', [])) if structured_data.get('json_ld_data') else None,
|
||||||
@ -676,6 +684,9 @@ class SEOAuditor:
|
|||||||
'noindex_reason': indexability.get('noindex_source'),
|
'noindex_reason': indexability.get('noindex_source'),
|
||||||
'has_sitemap': sitemap.get('exists', False),
|
'has_sitemap': sitemap.get('exists', False),
|
||||||
'has_robots_txt': robots.get('exists', False),
|
'has_robots_txt': robots.get('exists', False),
|
||||||
|
# Viewport and mobile-friendliness derived from meta_tags
|
||||||
|
'viewport_configured': bool(meta_tags.get('viewport')),
|
||||||
|
'is_mobile_friendly': 'width=device-width' in (meta_tags.get('viewport') or '').lower(),
|
||||||
|
|
||||||
# Core Web Vitals
|
# Core Web Vitals
|
||||||
'largest_contentful_paint_ms': cwv.get('lcp_ms'),
|
'largest_contentful_paint_ms': cwv.get('lcp_ms'),
|
||||||
@ -689,8 +700,9 @@ class SEOAuditor:
|
|||||||
'og_image': og.get('og_image', '')[:500] if og.get('og_image') else None,
|
'og_image': og.get('og_image', '')[:500] if og.get('og_image') else None,
|
||||||
'has_twitter_cards': bool(tc.get('card_type')),
|
'has_twitter_cards': bool(tc.get('card_type')),
|
||||||
|
|
||||||
# Language
|
# Language & International
|
||||||
'html_lang': onpage.get('lang_attribute', '')[:10] if onpage.get('lang_attribute') else None,
|
'html_lang': onpage.get('lang_attribute', '')[:10] if onpage.get('lang_attribute') else None,
|
||||||
|
'has_hreflang': onpage.get('has_hreflang', False), # Detected by analyzer if present
|
||||||
|
|
||||||
# Word count
|
# Word count
|
||||||
'word_count_homepage': onpage.get('word_count'),
|
'word_count_homepage': onpage.get('word_count'),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user