extracting-filemaker-business-logic
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseExtracting FileMaker Business Logic
提取FileMaker业务逻辑
Overview
概述
FileMaker DDR reports contain calculation fields, custom functions, and business logic embedded in scripts. This skill helps you extract, understand, and adapt that logic for PostgreSQL implementations—typically for import processes, data transformations, and maintenance scripts.
Key principle: PostgreSQL implementations will often be more efficient than direct translations. Use FileMaker logic to understand what the business rules are, then implement them idiomatically in PostgreSQL.
FileMaker DDR报告包含计算字段、自定义函数以及嵌入在脚本中的业务逻辑。本技能可帮助您提取、理解并适配这些逻辑,用于PostgreSQL实现——通常用于导入流程、数据转换和维护脚本。
核心原则:PostgreSQL实现通常比直接翻译更高效。借助FileMaker逻辑理解业务规则的本质,然后以符合PostgreSQL风格的方式实现这些规则。
When to Use
适用场景
Use this skill when:
- Extracting calculation logic from FileMaker DDR for import scripts
- Understanding business rules embedded in FileMaker calculations
- Adapting FileMaker custom functions to PostgreSQL functions
- Creating PostgreSQL maintenance scripts based on FileMaker script logic
- Documenting business logic that exists only in FileMaker
Do NOT use for:
- Direct 1:1 database migration (most PostgreSQL designs will differ)
- FileMaker UI/layout logic (not relevant to PostgreSQL)
- Simple field mappings (use standard ETL tools)
本技能适用于:
- 从FileMaker DDR中提取计算逻辑用于导入脚本
- 理解嵌入在FileMaker计算中的业务规则
- 将FileMaker自定义函数适配为PostgreSQL函数
- 基于FileMaker脚本逻辑创建PostgreSQL维护脚本
- 记录仅存在于FileMaker中的业务逻辑
不适用于:
- 直接1:1数据库迁移(大多数PostgreSQL设计会有所不同)
- FileMaker UI/布局逻辑(与PostgreSQL无关)
- 简单字段映射(使用标准ETL工具即可)
DDR Files and Structure
DDR文件与结构
Detailed DDR: (5-20MB file)
{ProjectName}_ddr/{DatabaseName}.html- Contains complete calculation formulas
- Lists all custom functions with code
- Documents scripts step-by-step
- Shows field definitions and relationships
Example from user's project:
- File:
/Users/anthonybyrnes/PycharmProjects/Python419/AugustServer_ddr/AugustServer.html - Size: 9.7MB
- Contains: 148 custom functions, 362 scripts, calculation fields
详细DDR文件:(5-20MB大小)
{ProjectName}_ddr/{DatabaseName}.html- 包含完整的计算公式
- 列出所有带代码的自定义函数
- 分步记录脚本内容
- 显示字段定义和关系
用户项目示例:
- 文件路径:
/Users/anthonybyrnes/PycharmProjects/Python419/AugustServer_ddr/AugustServer.html - 大小:9.7MB
- 包含:148个自定义函数、362个脚本、计算字段
Finding Calculations in DDR
在DDR中查找计算逻辑
Calculation Fields
计算字段
In DDR HTML, calculation fields appear in field definitions:
Field Name: wtu_calculation
Type: Calculation
Result Type: Number
Formula:
contacthours * units * csfactorXPath pattern (adjust based on actual DDR structure):
python
from lxml import etree
tree = etree.parse("AugustServer_ddr/AugustServer.html", etree.HTMLParser())在DDR HTML中,计算字段出现在字段定义中:
Field Name: wtu_calculation
Type: Calculation
Result Type: Number
Formula:
contacthours * units * csfactorXPath模式(根据实际DDR结构调整):
python
from lxml import etree
tree = etree.parse("AugustServer_ddr/AugustServer.html", etree.HTMLParser())Find calculation fields
Find calculation fields
calc_fields = tree.xpath('//td[contains(text(), "Calculation")]/parent::tr')
for field_row in calc_fields:
field_name = field_row.xpath('./td[1]/text()')[0]
formula = field_row.xpath('./following-sibling::tr//text()')
undefinedcalc_fields = tree.xpath('//td[contains(text(), "Calculation")]/parent::tr')
for field_row in calc_fields:
field_name = field_row.xpath('./td[1]/text()')[0]
formula = field_row.xpath('./following-sibling::tr//text()')
undefinedScripts (Critical Source of Business Logic)
脚本(业务逻辑的关键来源)
Important: Many "calculated" values are actually set by FileMaker scripts, not calculation fields. Scripts often contain the most complex business logic.
Look for scripts that:
- SetField steps (e.g., "Set Field [ClassInstance::wtu; ...]")
- Loop through records performing calculations
- Names containing "Calculate", "Update", "Process", "Compute"
- Triggered by imports or scheduled tasks
Example: The WTU field may appear as a Number field (not Calculation), but scripts like "419F - Loop WTU Contact Hours" contain the actual calculation logic.
Script: 419F - Loop WTU Contact Hours - c courses
Steps:
If [Units ≠ "-"]
Set Field [ClassInstance::wtu; ACCU * Workload_Weight_Factor]
Set Field [ClassInstance::contactHours; ACCU * contact_hours_per_unit]
End IfExtraction tip: Search DDR for field names (e.g., "wtu") to find all scripts that reference them.
重要提示:许多“计算”值实际上是由FileMaker脚本设置的,而非计算字段。脚本通常包含最复杂的业务逻辑。
需要关注的脚本类型:
- SetField步骤(例如:"Set Field [ClassInstance::wtu; ...]")
- 循环遍历记录执行计算的脚本
- 名称包含“Calculate”、“Update”、“Process”、“Compute”的脚本
- 由导入或计划任务触发的脚本
示例:WTU字段可能显示为Number类型(非Calculation类型),但类似“419F - Loop WTU Contact Hours”的脚本包含实际的计算逻辑。
Script: 419F - Loop WTU Contact Hours - c courses
Steps:
If [Units ≠ "-"]
Set Field [ClassInstance::wtu; ACCU * Workload_Weight_Factor]
Set Field [ClassInstance::contactHours; ACCU * contact_hours_per_unit]
End If提取技巧:在DDR中搜索字段名(例如“wtu”),找到所有引用该字段的脚本。
Custom Functions
自定义函数
Custom functions section (anchor: ):
#valCustomFunctionsSectionAnchor_Function Name: GenerateUUID
Parameters: none
Formula:
Upper(Get(UUID))Look for patterns in custom function names:
- Prefix conventions (e.g., ,
CF_)Calc_ - Purpose indicators (,
Validate_,Format_)Calculate_
自定义函数部分(锚点:):
#valCustomFunctionsSectionAnchor_Function Name: GenerateUUID
Parameters: none
Formula:
Upper(Get(UUID))关注自定义函数名称的模式:
- 前缀约定(例如、
CF_)Calc_ - 用途标识(、
Validate_、Format_)Calculate_
Understanding FileMaker Calculation Syntax
理解FileMaker计算语法
Common FileMaker Functions → PostgreSQL Equivalents
常见FileMaker函数 → PostgreSQL等效函数
| FileMaker | PostgreSQL | Notes |
|---|---|---|
| | FileMaker UUIDs are uppercase |
| | Direct equivalent |
| | Direct equivalent |
| | Direct equivalent |
| | PostgreSQL simpler, use SUBSTRING for start/occurrence |
| | Direct equivalent |
| | FileMaker's scoped variables |
| | Similar structure |
| | Or use |
| Dynamic SQL or CASE statement | FileMaker allows dynamic field references |
| | Relationship counts become subqueries |
| | Aggregate from related table |
| FileMaker | PostgreSQL | 说明 |
|---|---|---|
| | FileMaker UUID为大写 |
| | 直接等效 |
| | 直接等效 |
| | 直接等效 |
| | PostgreSQL语法更简洁,如需指定起始位置或出现次数可使用SUBSTRING |
| | 直接等效 |
| | FileMaker的作用域变量 |
| | 结构类似 |
| | 或在PL/pgSQL中使用 |
| 动态SQL或CASE语句 | FileMaker允许动态字段引用 |
| | 关系计数变为子查询 |
| | 从关联表聚合数据 |
FileMaker Operators
FileMaker运算符
- (concatenation) →
&in PostgreSQL|| - or
≠→!=or<>in PostgreSQL!= - ,
and,or→not,AND,ORin PostgreSQLNOT - (paragraph return) →
¶in PostgreSQLE'\n'
- (连接)→ PostgreSQL中使用
&|| - 或
≠→ PostgreSQL中使用!=或<>!= - ,
and,or→ PostgreSQL中使用not,AND,ORNOT - (段落换行)→ PostgreSQL中使用
¶E'\n'
Extraction Workflow
提取工作流
Step 1: Identify Business Logic Locations
步骤1:确定业务逻辑位置
Scan DDR for (in priority order):
- Scripts that manipulate data (SetField, Loop, calculations) - often the PRIMARY source
- Calculation fields in tables you're importing
- Custom functions referenced by calculations/scripts
- Auto-enter calculations (default values with logic)
- Validation calculations (field constraints)
Critical: Check scripts FIRST. Many fields appear as "Number" or "Text" but are actually calculated by scripts.
按优先级顺序扫描DDR:
- 操作数据的脚本(SetField、Loop、计算逻辑)——通常是主要来源
- 您要导入的表中的计算字段
- 计算/脚本引用的自定义函数
- 自动输入计算(带逻辑的默认值)
- 验证计算(字段约束)
关键提示:先检查脚本。许多字段显示为“Number”或“Text”类型,但实际上是由脚本计算得出的。
Step 2: Document Calculation Purpose
步骤2:记录计算用途
For each calculation field:
markdown
**Field**: ClassInstance.wtu
**Purpose**: Calculate weighted teaching units for workload reporting
**Formula**: `contacthours * units * csfactor`
**Dependencies**: contacthours, units, csfactor fields
**Used by**: WTU reports, faculty workload calculations
**Implementation**: PostgreSQL VIEW or calculated during import针对每个计算字段:
markdown
**字段**:ClassInstance.wtu
**用途**:计算用于工作量报告的加权教学单元
**公式**:`contacthours * units * csfactor`
**依赖项**:contacthours、units、csfactor字段
**使用者**:WTU报告、教师工作量计算
**实现方式**:PostgreSQL VIEW或在导入时计算Step 3: Adapt to PostgreSQL Idioms
步骤3:适配PostgreSQL风格
FileMaker approach (calculation field):
// FileMaker calculation field
Case(
enrollment_total = 0; "Empty";
enrollment_total < class_capacity * 0.5; "Low";
enrollment_total >= class_capacity; "Full";
"Adequate"
)PostgreSQL approach (CASE expression in VIEW):
sql
CREATE OR REPLACE VIEW class_status AS
SELECT
id,
class_nbr,
CASE
WHEN enrollment_total = 0 THEN 'Empty'
WHEN enrollment_total < class_capacity * 0.5 THEN 'Low'
WHEN enrollment_total >= class_capacity THEN 'Full'
ELSE 'Adequate'
END AS status
FROM classinstance;Or as import script logic (Python):
python
def calculate_class_status(enrollment_total, class_capacity):
"""Adapted from FileMaker ClassInstance.status calculation"""
if enrollment_total == 0:
return 'Empty'
elif enrollment_total < class_capacity * 0.5:
return 'Low'
elif enrollment_total >= class_capacity:
return 'Full'
else:
return 'Adequate'FileMaker方式(计算字段):
// FileMaker calculation field
Case(
enrollment_total = 0; "Empty";
enrollment_total < class_capacity * 0.5; "Low";
enrollment_total >= class_capacity; "Full";
"Adequate"
)PostgreSQL方式(VIEW中的CASE表达式):
sql
CREATE OR REPLACE VIEW class_status AS
SELECT
id,
class_nbr,
CASE
WHEN enrollment_total = 0 THEN 'Empty'
WHEN enrollment_total < class_capacity * 0.5 THEN 'Low'
WHEN enrollment_total >= class_capacity THEN 'Full'
ELSE 'Adequate'
END AS status
FROM classinstance;或作为导入脚本逻辑(Python):
python
def calculate_class_status(enrollment_total, class_capacity):
"""Adapted from FileMaker ClassInstance.status calculation"""
if enrollment_total == 0:
return 'Empty'
elif enrollment_total < class_capacity * 0.5:
return 'Low'
elif enrollment_total >= class_capacity:
return 'Full'
else:
return 'Adequate'Use during import
Use during import
cursor.execute("""
UPDATE classinstance
SET enrollment_status = %s
WHERE id = %s
""", (calculate_class_status(row['enrollment_total'], row['class_capacity']), row['id']))
undefinedcursor.execute("""
UPDATE classinstance
SET enrollment_status = %s
WHERE id = %s
""", (calculate_class_status(row['enrollment_total'], row['class_capacity']), row['id']))
undefinedStep 4: Handle Custom Functions
步骤4:处理自定义函数
FileMaker custom function:
Function: GenerateUUID
Parameters: none
Code:
Upper(Get(UUID))PostgreSQL equivalent (in existing codebase pattern):
python
def generate_uuid():
"""Generate uppercase UUID matching FileMaker format"""
return str(uuid.uuid4()).upper()Reference:
program_catalog_parser.py:116-120FileMaker自定义函数:
Function: GenerateUUID
Parameters: none
Code:
Upper(Get(UUID))PostgreSQL等效实现(符合现有代码库模式):
python
def generate_uuid():
"""Generate uppercase UUID matching FileMaker format"""
return str(uuid.uuid4()).upper()Reference:
program_catalog_parser.py:116-120Common Patterns
常见模式
Pattern 1: Aggregates from Relationships
模式1:关联表聚合
FileMaker:
// Count related records
Count(ClassAssign::id)
// Sum from related table
Sum(Enrollment::units)PostgreSQL (import script):
python
undefinedFileMaker:
// Count related records
Count(ClassAssign::id)
// Sum from related table
Sum(Enrollment::units)PostgreSQL(导入脚本):
python
undefinedCalculate during import
Calculate during import
cursor.execute("""
SELECT COUNT(*)
FROM classassign
WHERE id_classinstance = %s
""", (classinstance_id,))
assign_count = cursor.fetchone()[0]
cursor.execute("""
SELECT COUNT(*)
FROM classassign
WHERE id_classinstance = %s
""", (classinstance_id,))
assign_count = cursor.fetchone()[0]
Or as a VIEW
Or as a VIEW
CREATE VIEW classinstance_summary AS
SELECT
ci.id,
COUNT(ca.id) as assignment_count,
SUM(e.units) as total_enrollment_units
FROM classinstance ci
LEFT JOIN classassign ca ON ca.id_classinstance = ci.id
LEFT JOIN enrollment e ON e.id_classinstance = ci.id
GROUP BY ci.id;
undefinedCREATE VIEW classinstance_summary AS
SELECT
ci.id,
COUNT(ca.id) as assignment_count,
SUM(e.units) as total_enrollment_units
FROM classinstance ci
LEFT JOIN classassign ca ON ca.id_classinstance = ci.id
LEFT JOIN enrollment e ON e.id_classinstance = ci.id
GROUP BY ci.id;
undefinedPattern 2: Conditional Logic
模式2:条件逻辑
FileMaker:
Let([
base = contacthours * units;
factor = Case(
component = "LAB"; 1.5;
component = "LEC"; 1.0;
1.0
)
];
base * factor
)PostgreSQL function:
sql
CREATE OR REPLACE FUNCTION calculate_wtu(
contact_hours NUMERIC,
units NUMERIC,
component_type TEXT
) RETURNS NUMERIC AS $$
DECLARE
base NUMERIC;
factor NUMERIC;
BEGIN
base := contact_hours * units;
factor := CASE component_type
WHEN 'LAB' THEN 1.5
WHEN 'LEC' THEN 1.0
ELSE 1.0
END;
RETURN base * factor;
END;
$$ LANGUAGE plpgsql IMMUTABLE;FileMaker:
Let([
base = contacthours * units;
factor = Case(
component = "LAB"; 1.5;
component = "LEC"; 1.0;
1.0
)
];
base * factor
)PostgreSQL函数:
sql
CREATE OR REPLACE FUNCTION calculate_wtu(
contact_hours NUMERIC,
units NUMERIC,
component_type TEXT
) RETURNS NUMERIC AS $$
DECLARE
base NUMERIC;
factor NUMERIC;
BEGIN
base := contact_hours * units;
factor := CASE component_type
WHEN 'LAB' THEN 1.5
WHEN 'LEC' THEN 1.0
ELSE 1.0
END;
RETURN base * factor;
END;
$$ LANGUAGE plpgsql IMMUTABLE;Pattern 3: Text Parsing/Formatting
模式3:文本解析/格式化
FileMaker:
// Extract course code from title
Let([
spacePos = Position(" "; course_title; 1; 1)
];
Left(course_title; spacePos - 1)
)PostgreSQL (import script):
python
def extract_course_code(course_title):
"""Extract course code from title (FileMaker logic)"""
space_pos = course_title.find(' ')
if space_pos > 0:
return course_title[:space_pos]
return course_titleFileMaker:
// Extract course code from title
Let([
spacePos = Position(" "; course_title; 1; 1)
];
Left(course_title; spacePos - 1)
)PostgreSQL(导入脚本):
python
def extract_course_code(course_title):
"""Extract course code from title (FileMaker logic)"""
space_pos = course_title.find(' ')
if space_pos > 0:
return course_title[:space_pos]
return course_titleOr SQL function
Or SQL function
CREATE OR REPLACE FUNCTION extract_course_code(course_title TEXT)
RETURNS TEXT AS $$
BEGIN
RETURN SPLIT_PART(course_title, ' ', 1);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
undefinedCREATE OR REPLACE FUNCTION extract_course_code(course_title TEXT)
RETURNS TEXT AS $$
BEGIN
RETURN SPLIT_PART(course_title, ' ', 1);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
undefinedScript Logic Extraction
脚本逻辑提取
FileMaker scripts often contain:
- Data transformation logic → PostgreSQL functions or Python import scripts
- Validation rules → CHECK constraints or application validation
- Business workflows → Application layer logic
- UI automation → Ignore for PostgreSQL
Focus on extracting:
- SetField steps (data updates)
- If/Else logic (conditional rules)
- Loop structures (batch processing)
- Calculation expressions used in scripts
FileMaker脚本通常包含:
- 数据转换逻辑 → PostgreSQL函数或Python导入脚本
- 验证规则 → CHECK约束或应用层验证
- 业务工作流 → 应用层逻辑
- UI自动化 → 针对PostgreSQL可忽略
重点提取内容:
- SetField步骤(数据更新)
- If/Else逻辑(条件规则)
- 循环结构(批量处理)
- 脚本中使用的计算表达式
Integration with Import Processes
与导入流程的集成
When building import scripts:
python
undefined构建导入脚本时:
python
undefinedReference: program_catalog_parser.py patterns
Reference: program_catalog_parser.py patterns
def process_catalog_entry(row, catalog_year):
"""
Process catalog entry with business logic adapted from FileMaker.
FileMaker calculation: catalog_year format "2024-2025"
FileMaker custom function: ConvertToAY("2024-2025") → "24-25"
"""
# Adapt FileMaker's year conversion logic
ay_short = catalog_year[2:4] + '-' + catalog_year[7:9]
# Get AY record (FileMaker relationship equivalent)
cursor.execute("SELECT id FROM ay WHERE ay = %s", (ay_short,))
id_ay = cursor.fetchone()[0]
# Apply business rule (from FileMaker calculation)
if row['total_units'] is None:
# FileMaker: If(IsEmpty(total_units); Calculate_Default_Units; total_units)
total_units = calculate_default_units(row)
else:
total_units = row['total_units']
return {
'id_ay': id_ay,
'total_units': total_units,
# ... other fields
}undefineddef process_catalog_entry(row, catalog_year):
"""
Process catalog entry with business logic adapted from FileMaker.
FileMaker calculation: catalog_year format "2024-2025"
FileMaker custom function: ConvertToAY("2024-2025") → "24-25"
"""
# Adapt FileMaker's year conversion logic
ay_short = catalog_year[2:4] + '-' + catalog_year[7:9]
# Get AY record (FileMaker relationship equivalent)
cursor.execute("SELECT id FROM ay WHERE ay = %s", (ay_short,))
id_ay = cursor.fetchone()[0]
# Apply business rule (from FileMaker calculation)
if row['total_units'] is None:
# FileMaker: If(IsEmpty(total_units); Calculate_Default_Units; total_units)
total_units = calculate_default_units(row)
else:
total_units = row['total_units']
return {
'id_ay': id_ay,
'total_units': total_units,
# ... other fields
}undefinedCommon Mistakes
常见错误
Mistake 1: Literal Translation
- Don't translate FileMaker calculations character-by-character
- Understand the business rule, then implement idiomatically in PostgreSQL
Mistake 2: Ignoring Context
- Calculation fields may reference global fields or UI state
- Determine if logic is data-based (extract) or UI-based (ignore)
Mistake 3: Missing Dependencies
- Custom functions may call other custom functions
- Extract the full dependency chain
Mistake 4: Over-Engineering
- Simple calculations don't need PostgreSQL functions
- Calculate during import if logic is only used once
Mistake 5: Skipping Documentation
- Document the business purpose, not just the formula
- Future maintainers need to understand why, not just what
Mistake 6: Only Checking Calculation Fields
- Scripts often contain the primary business logic
- Check SetField steps in scripts for complex calculations
- A "Number" field type doesn't mean it's not calculated
错误1:直译
- 不要逐字符翻译FileMaker计算逻辑
- 理解业务规则后,以符合PostgreSQL风格的方式实现
错误2:忽略上下文
- 计算字段可能引用全局字段或UI状态
- 判断逻辑是基于数据的(提取)还是基于UI的(忽略)
错误3:遗漏依赖项
- 自定义函数可能调用其他自定义函数
- 提取完整的依赖链
错误4:过度设计
- 简单计算不需要PostgreSQL函数
- 如果逻辑仅使用一次,可在导入时计算
错误5:跳过文档记录
- 记录业务用途,而不仅仅是公式
- 未来维护人员需要理解“为什么”,而不只是“是什么”
错误6:仅检查计算字段
- 脚本通常包含主要的业务逻辑
- 检查脚本中的SetField步骤以获取复杂计算
- “Number”字段类型不代表它不是计算得出的
Common Rationalizations to Avoid
需避免的常见自我合理化
| Rationalization | Reality |
|---|---|
| "The field is type Number, so it's not calculated" | FileMaker scripts often calculate and set Number/Text fields. Check scripts that reference the field. |
| "I'll just look at calculation fields" | Most complex logic is in scripts (SetField steps), not calculation field types. Scripts are the PRIMARY source. |
| "This is too complex to extract, I'll rebuild from scratch" | You'll miss critical business rules. Extract the logic first, then refactor for PostgreSQL. |
| "I can translate this literally to PostgreSQL" | FileMaker idioms differ from PostgreSQL. Understand the business rule, then implement idiomatically. |
| "I don't need to document this, the code is self-explanatory" | Business context gets lost. Document WHY the calculation exists, not just WHAT it does. |
| "I'll skip the custom functions for now" | Custom functions contain reusable business logic. Extract them early; they'll be referenced throughout. |
| "This global field must be in PostgreSQL" | Global fields are UI/session state, not database state. Handle in application layer, not schema. |
| "I can figure out relationships from field names alone" | FileMaker relationships include conditions. Check DDR relationship definitions for filtering rules. |
| 自我合理化 | 实际情况 |
|---|---|
| “该字段是Number类型,所以它不是计算得出的” | FileMaker脚本经常计算并设置Number/Text字段。检查引用该字段的脚本。 |
| “我只需要看计算字段” | 大多数复杂逻辑存在于脚本(SetField步骤)中,而非计算字段类型。脚本是主要来源。 |
| “这太复杂了,无法提取,我将从头重建” | 您会遗漏关键业务规则。先提取逻辑,再针对PostgreSQL重构。 |
| “我可以直接将其直译到PostgreSQL” | FileMaker的惯用写法与PostgreSQL不同。理解业务规则后,以符合PostgreSQL风格的方式实现。 |
| “不需要记录这个,代码本身就很清楚” | 业务上下文会丢失。记录计算存在的原因,而不只是计算内容。 |
| “我现在先跳过自定义函数” | 自定义函数包含可复用的业务逻辑。尽早提取它们,因为它们会被广泛引用。 |
| “这个全局字段必须在PostgreSQL中存在” | 全局字段是UI/会话状态,而非数据库状态。在应用层处理,而非数据库模式中。 |
| “我仅通过字段名就能弄清楚关系” | FileMaker关系包含条件。检查DDR关系定义中的过滤规则。 |
Checklist for Logic Extraction
逻辑提取检查清单
When extracting FileMaker business logic:
- Locate DDR detailed HTML file
- Identify calculation fields in relevant tables
- Document purpose and dependencies for each calculation
- List custom functions used by calculations
- Extract custom function code and dependencies
- Map FileMaker functions to PostgreSQL equivalents
- Decide: PostgreSQL function, VIEW, or import script logic?
- Implement with idiomatic PostgreSQL patterns
- Test with sample data from FileMaker
- Document business rules separately from code
提取FileMaker业务逻辑时:
- 找到DDR详细HTML文件
- 确定相关表中的计算字段
- 记录每个计算的用途和依赖项
- 列出计算使用的自定义函数
- 提取自定义函数代码和依赖项
- 映射FileMaker函数到PostgreSQL等效函数
- 决定:使用PostgreSQL函数、VIEW还是导入脚本逻辑?
- 以符合PostgreSQL风格的方式实现
- 使用FileMaker中的示例数据进行测试
- 单独记录业务规则(与代码分开)
Real-World Example
实际案例
From user's existing codebase:
python
undefined来自用户现有代码库:
python
undefinedprogram_catalog_parser.py:41-70
program_catalog_parser.py:41-70
def get_ay_id(conn, catalog_year: str) -> Optional[str]:
"""
Get AY id from catalog_year string.
Converts full format "2025-2026" to short format "25-26"
and looks up corresponding AY record.
This logic was adapted from FileMaker calculation that
performed similar year format conversion in catalog imports.
"""
# Convert "2025-2026" to "25-26" (FileMaker custom function logic)
try:
ay_short = catalog_year[2:4] + '-' + catalog_year[7:9]
except IndexError:
logger.error(f"Invalid catalog_year format: {catalog_year}")
return None
with conn.cursor() as cur:
cur.execute("SELECT id FROM ay WHERE ay = %s", (ay_short,))
result = cur.fetchone()
if not result:
logger.warning(f"AY not found for catalog_year: {catalog_year}")
return None
return result[0]
This function adapted FileMaker's year conversion logic for use in PostgreSQL import scripts.def get_ay_id(conn, catalog_year: str) -> Optional[str]:
"""
Get AY id from catalog_year string.
Converts full format "2025-2026" to short format "25-26"
and looks up corresponding AY record.
This logic was adapted from FileMaker calculation that
performed similar year format conversion in catalog imports.
"""
# Convert "2025-2026" to "25-26" (FileMaker custom function logic)
try:
ay_short = catalog_year[2:4] + '-' + catalog_year[7:9]
except IndexError:
logger.error(f"Invalid catalog_year format: {catalog_year}")
return None
with conn.cursor() as cur:
cur.execute("SELECT id FROM ay WHERE ay = %s", (ay_short,))
result = cur.fetchone()
if not result:
logger.warning(f"AY not found for catalog_year: {catalog_year}")
return None
return result[0]
此函数适配了FileMaker的年份转换逻辑,用于PostgreSQL导入脚本。