import {
  Column, Table, NoOperation, JoinOperation, JoinTreeNodeOperation, CountAllOperation,
  Operation, RelationalOperationElement,
} from '@model/relational';
import {
  ProcessingTemporalColumns, SingleBusinessDateColumn,
  BusinessDateAndProcessingTemporalColumns, BiTemporalColumns, MilestonedTable,
} from '@model/milestoning';
import { convertInputsAndSelect, convertInputsAndSelectForDateRange, FinderResult } from '@datafinder/runner';
import { ExistsOperation, NotExistsOperation } from '@model/relational';
import { displayPrefix } from '@datafinder/finder';
import type { Attribute } from '@datafinder/attribute';
import { EmbeddedAttributes, embeddedUnder } from '@datafinder/embedded';
import { titleCase } from '@datafinder/naming';
{% set attr_types = get_used_attr_types(rcm) %}
{% if attr_types %}
import { {{attr_types | join(', ')}} } from '@datafinder/typed-attributes';
{% endif %}
import { {{rcm.clazz.name}}FinderBase, {{rcm.clazz.name}}RelatedFinderBase } from './{{rcm.clazz.name}}FinderBase';
import type { {{rcm.clazz.name}}Filter } from './{{rcm.clazz.name}}FinderBase';
{% set ns = namespace(seen=[]) %}
{% for rpm in rcm.property_mappings %}
{% if not is_primitive(rpm.property) and rpm.property.type.name != rcm.clazz.name and rpm.property.type.name not in ns.seen %}
import { {{rpm.property.type.name}}RelatedFinder } from '{{class_module_map[rpm.property.type.name]}}';
import type { {{rpm.property.type.name}}Filter } from '{{class_module_map_base[rpm.property.type.name]}}Base';
{% set ns.seen = ns.seen + [rpm.property.type.name] %}
{% endif %}
{% endfor %}
{% set ns2 = namespace(seen_rev=[]) %}
{% for source_rcm, rpm, assoc, reverse_name in reverse_assocs %}
{% if source_rcm.clazz.name not in ns2.seen_rev and source_rcm.clazz.name != rcm.clazz.name %}
import type { {{source_rcm.clazz.name}}RelatedFinder } from '{{class_module_map[source_rcm.clazz.name]}}';
import type { {{source_rcm.clazz.name}}Filter } from '{{class_module_map_base[source_rcm.clazz.name]}}Base';
{% set ns2.seen_rev = ns2.seen_rev + [source_rcm.clazz.name] %}
{% endif %}
{% endfor %}
{% if reverse_assocs %}
import { registerRelatedFinderClass, getRelatedFinderClass } from '@datafinder/finder-registry';
{% else %}
import { registerRelatedFinderClass } from '@datafinder/finder-registry';
{% endif %}

{% for rpm in rcm.property_mappings %}
{% if not is_primitive(rpm.property) and rpm.property.type.name != rcm.clazz.name and flatten_embedded(rpm.target) %}
/** Join-less alternates for '{{rpm.property.id}}.*' properties satisfied by flat columns on this table,
 * merged with any deeper embedding forwarded by the caller. */
function embeddedFor_{{to_ts_name(rpm.property)}}(incoming: EmbeddedAttributes | undefined, parent: JoinTreeNodeOperation | undefined, relationName: string): EmbeddedAttributes {
  const result: EmbeddedAttributes = {};
{% for dotted, leaf_prop, col in flatten_embedded(rpm.target) %}
  result['{{dotted}}'] = new {{leaf_prop.type.name}}Attribute(titleCase(relationName) + ' {{display_name(leaf_prop)}}', '{{col.name}}', '{{col.type}}', '{{table_qualified_name(col.table)}}', parent);
{% endfor %}
  const forwarded = embeddedUnder(incoming, '{{rpm.property.id}}.');
  if (forwarded) Object.assign(result, forwarded);
  return result;
}

{% endif %}
{% endfor %}
{% set _class_doc = get_doc(rcm.clazz) %}
{% if _class_doc %}
/** {{_class_doc}} */
{% endif %}
export class {{rcm.clazz.name}}RelatedFinder extends {{rcm.clazz.name}}RelatedFinderBase {

{% if rcm.milestone_mapping %}
{% if has_bitemporal(rcm.milestone_mapping) %}
  private static readonly _milestoningColumns = new BiTemporalColumns(
    new Column('{{rcm.milestone_mapping._date_from.target.name}}', '{{rcm.milestone_mapping._date_from.target.type}}'),
    new Column('{{rcm.milestone_mapping._date_to.target.name}}', '{{rcm.milestone_mapping._date_to.target.type}}'),
    new Column('{{rcm.milestone_mapping._in.target.name}}', '{{rcm.milestone_mapping._in.target.type}}'),
    new Column('{{rcm.milestone_mapping._out.target.name}}', '{{rcm.milestone_mapping._out.target.type}}'){% if rcm.milestone_mapping.infinite_datetime %},
    '{{rcm.milestone_mapping.infinite_datetime}}'{% endif %},
  );
{% elif has_business_date_and_processing(rcm.milestone_mapping) %}
  private static readonly _milestoningColumns = new BusinessDateAndProcessingTemporalColumns(
    new Column('{{rcm.milestone_mapping._date.target.name}}', '{{rcm.milestone_mapping._date.target.type}}'),
    new Column('{{rcm.milestone_mapping._in.target.name}}', '{{rcm.milestone_mapping._in.target.type}}'),
    new Column('{{rcm.milestone_mapping._out.target.name}}', '{{rcm.milestone_mapping._out.target.type}}'){% if rcm.milestone_mapping.infinite_datetime %},
    '{{rcm.milestone_mapping.infinite_datetime}}'{% endif %},
  );
{% elif has_processing_temporal(rcm.milestone_mapping) %}
  private static readonly _milestoningColumns = new ProcessingTemporalColumns(
    new Column('{{rcm.milestone_mapping._in.target.name}}', '{{rcm.milestone_mapping._in.target.type}}'),
    new Column('{{rcm.milestone_mapping._out.target.name}}', '{{rcm.milestone_mapping._out.target.type}}'){% if rcm.milestone_mapping.infinite_datetime %},
    '{{rcm.milestone_mapping.infinite_datetime}}'{% endif %},
  );
{% elif has_uni_business_temporal(rcm.milestone_mapping) %}
  private static readonly _milestoningColumns = new SingleBusinessDateColumn(
    new Column('{{rcm.milestone_mapping._date.target.name}}', '{{rcm.milestone_mapping._date.target.type}}'),
  );
{% endif %}
  private static readonly _table = new MilestonedTable('{{table_qualified_name(rcm.property_mappings[0].target.table)}}', [], {{rcm.clazz.name}}RelatedFinder._milestoningColumns);
{% else %}
  private static readonly _table = new Table('{{table_qualified_name(rcm.property_mappings[0].target.table)}}', []);
{% endif %}

  /** Property id -> [column, type, table] for the filters accepted by related-finder accessors. */
  private static readonly _filterColumns: Record<string, [string, string, string]> = {
{% for rpm in rcm.property_mappings %}
{% if is_primitive(rpm.property) %}
    '{{rpm.property.id}}': ['{{rpm.target.name}}', '{{rpm.target.type}}', '{{table_qualified_name(rpm.target.table)}}'],
{% endif %}
{% endfor %}
  };

  private readonly _node: JoinTreeNodeOperation;
{% for rpm in rcm.property_mappings %}
{% if is_primitive(rpm.property) %}
  private readonly _{{to_ts_name(rpm.property)}}: {{rpm.property.type.name}}Attribute;
{% elif rpm.property.type.name == rcm.clazz.name %}
  private _{{to_ts_name(rpm.property)}}?: {{rpm.property.type.name}}RelatedFinder;
{% else %}
  private readonly _{{to_ts_name(rpm.property)}}: {{rpm.property.type.name}}RelatedFinder;
{% endif %}
{% endfor %}
{% for source_rcm, rpm, assoc, reverse_name in reverse_assocs %}
  private _{{reverse_name}}?: {{source_rcm.clazz.name}}RelatedFinder;
{% endfor %}

  constructor(relationName: string, source: Column, target: Column, parentJoin?: JoinTreeNodeOperation, embedded?: EmbeddedAttributes, filter?: {{rcm.clazz.name}}Filter) {
    super();
    const join = new JoinOperation(relationName, {{rcm.clazz.name}}RelatedFinder._table, source, target);
    if (filter) {
      join.filterKwargs = filter as Record<string, unknown>;
      join.filterColumnMap = {{rcm.clazz.name}}RelatedFinder._filterColumns;
    }
    this._node = new JoinTreeNodeOperation(join, parentJoin);
{% for rpm in rcm.property_mappings %}
{% if is_primitive(rpm.property) %}
    this._{{to_ts_name(rpm.property)}} = new {{rpm.property.type.name}}Attribute(displayPrefix(relationName, parentJoin) + ' {{display_name(rpm.property)}}', '{{rpm.target.name}}', '{{rpm.target.type}}', '{{table_qualified_name(rpm.target.table)}}', this._node, embedded?.['{{rpm.property.id}}']);
{% elif rpm.property.type.name != rcm.clazz.name %}
    this._{{to_ts_name(rpm.property)}} = new {{rpm.property.type.name}}RelatedFinder('{{rpm.property.name}}', new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), this._node, {% if flatten_embedded(rpm.target) %}embeddedFor_{{to_ts_name(rpm.property)}}(embedded, this._node, '{{rpm.property.name}}'){% else %}embeddedUnder(embedded, '{{rpm.property.id}}.'){% endif %});
{% endif %}
{% endfor %}
  }

{% for rpm in rcm.property_mappings %}
{% if is_primitive(rpm.property) %}
  {{prop_jsdoc(rpm.property)}}
  {{to_ts_name(rpm.property)}}(): {{rpm.property.type.name}}Attribute {
    return this._{{to_ts_name(rpm.property)}};
  }

{% elif rpm.property.type.name == rcm.clazz.name %}
  {{prop_jsdoc(rpm.property)}}
  {{to_ts_name(rpm.property)}}(filter?: {{rpm.property.type.name}}Filter): {{rpm.property.type.name}}RelatedFinder {
    if (filter) return new {{rpm.property.type.name}}RelatedFinder('{{rpm.property.name}}', new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), this._node, undefined, filter);
    if (!this._{{to_ts_name(rpm.property)}}) {
      this._{{to_ts_name(rpm.property)}} = new {{rpm.property.type.name}}RelatedFinder('{{rpm.property.name}}', new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), this._node);
    }
    return this._{{to_ts_name(rpm.property)}}!;
  }

{% else %}
  {{prop_jsdoc(rpm.property)}}
  {{to_ts_name(rpm.property)}}(filter?: {{rpm.property.type.name}}Filter): {{rpm.property.type.name}}RelatedFinder {
    if (filter) return new {{rpm.property.type.name}}RelatedFinder('{{rpm.property.name}}', new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), this._node, undefined, filter);
    return this._{{to_ts_name(rpm.property)}};
  }

{% endif %}
{% endfor %}
{% for source_rcm, rpm, assoc, reverse_name in reverse_assocs %}
  {{reverse_name}}(filter?: {{source_rcm.clazz.name}}Filter): {{source_rcm.clazz.name}}RelatedFinder {
    const _Cls = getRelatedFinderClass('{{source_rcm.clazz.name}}') as new (relationName: string, source: Column, target: Column, parentJoin?: JoinTreeNodeOperation, embedded?: EmbeddedAttributes, filter?: {{source_rcm.clazz.name}}Filter) => {{source_rcm.clazz.name}}RelatedFinder;
    if (!_Cls) throw new Error('{{source_rcm.clazz.name}}RelatedFinder not registered. Import {{source_rcm.clazz.name}}Finder before calling {{reverse_name}}().');
    if (filter) return new _Cls('{{source_rcm.clazz.name}}', new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), this._node, undefined, filter);
    if (!this._{{reverse_name}}) {
      this._{{reverse_name}} = new _Cls('{{source_rcm.clazz.name}}', new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), this._node);
    }
    return this._{{reverse_name}}!;
  }

{% endfor %}
  /** Filter to rows that have a matching {{rcm.clazz.name}} through this join. */
  exists(): ExistsOperation {
    return new ExistsOperation(this._node);
  }

  /** Filter to rows that have no matching {{rcm.clazz.name}} through this join. */
  notExists(): NotExistsOperation {
    return new NotExistsOperation(this._node);
  }
}

{% set _class_doc = get_doc(rcm.clazz) %}
{% if _class_doc %}
/** {{_class_doc}} */
{% endif %}
export class {{rcm.clazz.name}}Finder extends {{rcm.clazz.name}}FinderBase {

{% if rcm.milestone_mapping %}
{% if has_bitemporal(rcm.milestone_mapping) %}
  private static readonly _milestoningColumns = new BiTemporalColumns(
    new Column('{{rcm.milestone_mapping._date_from.target.name}}', '{{rcm.milestone_mapping._date_from.target.type}}'),
    new Column('{{rcm.milestone_mapping._date_to.target.name}}', '{{rcm.milestone_mapping._date_to.target.type}}'),
    new Column('{{rcm.milestone_mapping._in.target.name}}', '{{rcm.milestone_mapping._in.target.type}}'),
    new Column('{{rcm.milestone_mapping._out.target.name}}', '{{rcm.milestone_mapping._out.target.type}}'){% if rcm.milestone_mapping.infinite_datetime %},
    '{{rcm.milestone_mapping.infinite_datetime}}'{% endif %},
  );
{% elif has_business_date_and_processing(rcm.milestone_mapping) %}
  private static readonly _milestoningColumns = new BusinessDateAndProcessingTemporalColumns(
    new Column('{{rcm.milestone_mapping._date.target.name}}', '{{rcm.milestone_mapping._date.target.type}}'),
    new Column('{{rcm.milestone_mapping._in.target.name}}', '{{rcm.milestone_mapping._in.target.type}}'),
    new Column('{{rcm.milestone_mapping._out.target.name}}', '{{rcm.milestone_mapping._out.target.type}}'){% if rcm.milestone_mapping.infinite_datetime %},
    '{{rcm.milestone_mapping.infinite_datetime}}'{% endif %},
  );
{% elif has_processing_temporal(rcm.milestone_mapping) %}
  private static readonly _milestoningColumns = new ProcessingTemporalColumns(
    new Column('{{rcm.milestone_mapping._in.target.name}}', '{{rcm.milestone_mapping._in.target.type}}'),
    new Column('{{rcm.milestone_mapping._out.target.name}}', '{{rcm.milestone_mapping._out.target.type}}'){% if rcm.milestone_mapping.infinite_datetime %},
    '{{rcm.milestone_mapping.infinite_datetime}}'{% endif %},
  );
{% elif has_uni_business_temporal(rcm.milestone_mapping) %}
  private static readonly _milestoningColumns = new SingleBusinessDateColumn(
    new Column('{{rcm.milestone_mapping._date.target.name}}', '{{rcm.milestone_mapping._date.target.type}}'),
  );
{% endif %}
  private static readonly _table = new MilestonedTable('{{table_qualified_name(rcm.property_mappings[0].target.table)}}', [], {{rcm.clazz.name}}Finder._milestoningColumns);
{% else %}
  private static readonly _table = new Table('{{table_qualified_name(rcm.property_mappings[0].target.table)}}', []);
{% endif %}

{% for rpm in rcm.property_mappings %}
{% if is_primitive(rpm.property) %}
  private static readonly _{{to_ts_name(rpm.property)}} = new {{rpm.property.type.name}}Attribute('{{display_name(rpm.property)}}', '{{rpm.target.name}}', '{{rpm.target.type}}', '{{table_qualified_name(rpm.target.table)}}');
{% elif rpm.property.type.name != rcm.clazz.name %}
  private static readonly _{{to_ts_name(rpm.property)}} = new {{rpm.property.type.name}}RelatedFinder('{{rpm.property.name}}', new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'){% if flatten_embedded(rpm.target) %}, undefined, embeddedFor_{{to_ts_name(rpm.property)}}(undefined, undefined, '{{rpm.property.name}}'){% endif %});
{% endif %}
{% endfor %}
{% for rpm in rcm.property_mappings %}
{% if not is_primitive(rpm.property) and rpm.property.type.name == rcm.clazz.name %}
  private _{{to_ts_name(rpm.property)}}?: {{rpm.property.type.name}}RelatedFinder;
{% endif %}
{% endfor %}
{% for source_rcm, rpm, assoc, reverse_name in reverse_assocs %}
  private _{{reverse_name}}?: {{source_rcm.clazz.name}}RelatedFinder;
{% endfor %}

{% for rpm in rcm.property_mappings %}
{% if is_primitive(rpm.property) %}
  {{prop_jsdoc(rpm.property)}}
  {{to_ts_name(rpm.property)}}(): {{rpm.property.type.name}}Attribute {
    return {{rcm.clazz.name}}Finder._{{to_ts_name(rpm.property)}};
  }

{% elif rpm.property.type.name == rcm.clazz.name %}
  {{prop_jsdoc(rpm.property)}}
  {{to_ts_name(rpm.property)}}(filter?: {{rpm.property.type.name}}Filter): {{rpm.property.type.name}}RelatedFinder {
    if (filter) return new {{rpm.property.type.name}}RelatedFinder('{{rpm.property.name}}', new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), undefined, undefined, filter);
    if (!this._{{to_ts_name(rpm.property)}}) {
      this._{{to_ts_name(rpm.property)}} = new {{rpm.property.type.name}}RelatedFinder('{{rpm.property.name}}', new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'));
    }
    return this._{{to_ts_name(rpm.property)}}!;
  }

{% else %}
  {{prop_jsdoc(rpm.property)}}
  {{to_ts_name(rpm.property)}}(filter?: {{rpm.property.type.name}}Filter): {{rpm.property.type.name}}RelatedFinder {
    if (filter) return new {{rpm.property.type.name}}RelatedFinder('{{rpm.property.name}}', new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), undefined, undefined, filter);
    return {{rcm.clazz.name}}Finder._{{to_ts_name(rpm.property)}};
  }

{% endif %}
{% endfor %}
{% for source_rcm, rpm, assoc, reverse_name in reverse_assocs %}
  {{reverse_name}}(filter?: {{source_rcm.clazz.name}}Filter): {{source_rcm.clazz.name}}RelatedFinder {
    const _Cls = getRelatedFinderClass('{{source_rcm.clazz.name}}') as new (relationName: string, source: Column, target: Column, parentJoin?: JoinTreeNodeOperation, embedded?: EmbeddedAttributes, filter?: {{source_rcm.clazz.name}}Filter) => {{source_rcm.clazz.name}}RelatedFinder;
    if (!_Cls) throw new Error('{{source_rcm.clazz.name}}RelatedFinder not registered. Import {{source_rcm.clazz.name}}Finder before calling {{reverse_name}}().');
    if (filter) return new _Cls('{{source_rcm.clazz.name}}', new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'), undefined, undefined, filter);
    if (!this._{{reverse_name}}) {
      this._{{reverse_name}} = new _Cls('{{source_rcm.clazz.name}}', new Column('{{rpm.target.rhs.name}}', '{{rpm.target.rhs.type}}', '{{table_qualified_name(rpm.target.rhs.table)}}'), new Column('{{rpm.target.lhs.name}}', '{{rpm.target.lhs.type}}', '{{table_qualified_name(rpm.target.lhs.table)}}'));
    }
    return this._{{reverse_name}}!;
  }

{% endfor %}
  count(): CountAllOperation {
    return new CountAllOperation('{{table_qualified_name(rcm.property_mappings[0].target.table)}}');
  }

  findAll(
    businessDate: Date | string | null,
    processingValidAt: Date | string | null,
    displayColumns: (Attribute | RelationalOperationElement)[],
    filterOp: Operation = new NoOperation(),
  ): FinderResult {
{% if rcm.milestone_mapping %}
{% if has_processing_temporal(rcm.milestone_mapping) and not has_uni_business_temporal(rcm.milestone_mapping) and not has_business_date_and_processing(rcm.milestone_mapping) and not has_bitemporal(rcm.milestone_mapping) %}
    return convertInputsAndSelect(null, processingValidAt, displayColumns, {{rcm.clazz.name}}Finder._table, filterOp);
{% elif has_uni_business_temporal(rcm.milestone_mapping) and not has_business_date_and_processing(rcm.milestone_mapping) %}
    return convertInputsAndSelect(businessDate, null, displayColumns, {{rcm.clazz.name}}Finder._table, filterOp);
{% else %}
    return convertInputsAndSelect(businessDate, processingValidAt, displayColumns, {{rcm.clazz.name}}Finder._table, filterOp);
{% endif %}
{% else %}
    return convertInputsAndSelect(null, null, displayColumns, {{rcm.clazz.name}}Finder._table, filterOp);
{% endif %}
  }
{% if rcm.milestone_mapping and (has_bitemporal(rcm.milestone_mapping) or has_business_date_and_processing(rcm.milestone_mapping) or has_uni_business_temporal(rcm.milestone_mapping)) %}

  /**
   * Returns data for all records whose business date overlaps the given range.
   *
   * For bitemporal tables the range uses interval overlap:
   *   business_date_from_col <= businessDateTo AND business_date_to_col > businessDateFrom
   * For single-date tables:
   *   business_date >= businessDateFrom AND business_date <= businessDateTo
   * Processing-time filtering is point-in-time at processingValidAt.
   */
  findForDateRange(
    businessDateFrom: Date | string,
    businessDateTo: Date | string,
    processingValidAt: Date | string,
    displayColumns: (Attribute | RelationalOperationElement)[],
    filterOp: Operation = new NoOperation(),
  ): FinderResult {
    return convertInputsAndSelectForDateRange(businessDateFrom, businessDateTo, processingValidAt, displayColumns, {{rcm.clazz.name}}Finder._table, filterOp);
  }
{% endif %}
}

registerRelatedFinderClass('{{rcm.clazz.name}}', {{rcm.clazz.name}}RelatedFinder);
