FdcDataSet constructor

FdcDataSet({
  1. List<FdcFieldDef> fields = const <FdcFieldDef>[],
  2. IFdcDataAdapter? adapter,
  3. FdcUpdateMode updateMode = FdcUpdateMode.immediate,
  4. FdcRecordValidator? recordValidator,
  5. FdcDataSetBeforeOpen? beforeOpen,
  6. FdcDataSetAfterOpen? afterOpen,
  7. FdcDataSetBeforeClose? beforeClose,
  8. FdcDataSetAfterClose? afterClose,
  9. FdcDataSetBeforeEdit? beforeEdit,
  10. FdcDataSetAfterEdit? afterEdit,
  11. FdcDataSetBeforeInsert? beforeInsert,
  12. FdcDataSetAfterInsert? afterInsert,
  13. FdcDataSetBeforePost? beforePost,
  14. FdcDataSetAfterPost? afterPost,
  15. FdcDataSetBeforeDelete? beforeDelete,
  16. FdcDataSetAfterDelete? afterDelete,
  17. FdcDataSetBeforeCancel? beforeCancel,
  18. FdcDataSetAfterCancel? afterCancel,
  19. FdcDataSetStateChanged? onStateChanged,
  20. FdcDataSetValidationError? onValidationError,
  21. FdcDataSetErrorEvent? onError,
  22. FdcDataSetWorkStarted? onWorkStarted,
  23. FdcDataSetWorkCompleted? onWorkCompleted,
  24. FdcDataSetWorkError? onWorkError,
  25. FdcDataSetFieldChanged? onFieldChanged,
  26. FdcDataSetNewRecord? onNewRecord,
  27. FdcDataSetBeforeScroll? beforeScroll,
  28. FdcDataSetAfterScroll? afterScroll,
  29. FdcDataSetOperationOptions operationOptions = const FdcDataSetOperationOptions(),
  30. FdcDataPagingOptions paging = const FdcDataPagingOptions.disabled(),
  31. FdcFormatSettings? formatSettings,
  32. FdcValidationTranslations validationTranslations = const FdcValidationTranslations(),
})

Creates a dataset.

updateMode defaults to FdcUpdateMode.immediate. Pass FdcUpdateMode.cachedUpdates only when the dataset should buffer changes until an explicit applyUpdates call.

Implementation

// ignore: sort_constructors_first
FdcDataSet({
  List<FdcFieldDef> fields = const <FdcFieldDef>[],
  IFdcDataAdapter? adapter,
  FdcUpdateMode updateMode = FdcUpdateMode.immediate,
  FdcRecordValidator? recordValidator,
  FdcDataSetBeforeOpen? beforeOpen,
  FdcDataSetAfterOpen? afterOpen,
  FdcDataSetBeforeClose? beforeClose,
  FdcDataSetAfterClose? afterClose,
  FdcDataSetBeforeEdit? beforeEdit,
  FdcDataSetAfterEdit? afterEdit,
  FdcDataSetBeforeInsert? beforeInsert,
  FdcDataSetAfterInsert? afterInsert,
  FdcDataSetBeforePost? beforePost,
  FdcDataSetAfterPost? afterPost,
  FdcDataSetBeforeDelete? beforeDelete,
  FdcDataSetAfterDelete? afterDelete,
  FdcDataSetBeforeCancel? beforeCancel,
  FdcDataSetAfterCancel? afterCancel,
  FdcDataSetStateChanged? onStateChanged,
  FdcDataSetValidationError? onValidationError,
  FdcDataSetErrorEvent? onError,
  FdcDataSetWorkStarted? onWorkStarted,
  FdcDataSetWorkCompleted? onWorkCompleted,
  FdcDataSetWorkError? onWorkError,
  FdcDataSetFieldChanged? onFieldChanged,
  FdcDataSetNewRecord? onNewRecord,
  FdcDataSetBeforeScroll? beforeScroll,
  FdcDataSetAfterScroll? afterScroll,
  FdcDataSetOperationOptions operationOptions =
      const FdcDataSetOperationOptions(),
  FdcDataPagingOptions paging = const FdcDataPagingOptions.disabled(),
  FdcFormatSettings? formatSettings,
  FdcValidationTranslations validationTranslations =
      const FdcValidationTranslations(),
}) : _adapter = adapter,
     _paging = paging,
     _updateMode = updateMode,
     _recordValidator = recordValidator,
     _beforeOpen = beforeOpen,
     _afterOpen = afterOpen,
     _beforeClose = beforeClose,
     _afterClose = afterClose,
     _beforeEdit = beforeEdit,
     _afterEdit = afterEdit,
     _beforeInsert = beforeInsert,
     _afterInsert = afterInsert,
     _beforePost = beforePost,
     _afterPost = afterPost,
     _beforeDelete = beforeDelete,
     _afterDelete = afterDelete,
     _beforeCancel = beforeCancel,
     _afterCancel = afterCancel,
     _onStateChanged = onStateChanged,
     _onValidationError = onValidationError,
     _onError = onError,
     _onWorkStarted = onWorkStarted,
     _onWorkCompleted = onWorkCompleted,
     _onWorkError = onWorkError,
     _onFieldChanged = onFieldChanged,
     _onNewRecord = onNewRecord,
     _beforeScroll = beforeScroll,
     _afterScroll = afterScroll {
  paging.validate();
  _view.operationOptions = operationOptions;
  if (formatSettings != null) {
    _view.filterContext = _view.filterContext.copyWith(
      formatSettings: formatSettings,
    );
  }
  _schemaCoordinator = FdcDataSetSchemaCoordinator(
    recordValidator: _recordValidator,
    ownerDescription: runtimeType.toString(),
    validationTranslations: validationTranslations,
    invalidateComparableCacheForField: _invalidateComparableCacheForField,
  );
  _schemaCoordinator.configure(fields);
  _lifecycleCoordinator = FdcDataSetLifecycleCoordinator(
    openCore: _openCore,
    openFutureCore: _openFutureCore,
    loadRowsCore: _loadRowsCore,
    loadRowsFutureCore: _loadRowsFutureCore,
    closeCore: _closeCore,
  );
  _workCoordinator = FdcDataSetWorkCoordinator(
    captureLifecycleGeneration: _lifecycleCoordinator.captureGeneration,
    isLifecycleCurrent: _isLifecycleCurrent,
    onStarted: (work) => _onWorkStarted?.call(this, work),
    onCompleted: (work) => _onWorkCompleted?.call(this, work),
    onError: (work, error, stackTrace) =>
        _onWorkError?.call(this, work, error, stackTrace),
  );
  _errorController = FdcDataSetErrorController(
    store: _errorStore,
    emitValidationError: (errors) {
      _onValidationError?.call(this, errors);
    },
    emitError: (errors, {Object? cause}) {
      _onError?.call(this, errors, cause);
      for (final listener in List<FdcDataSetErrorEvent>.of(
        _internalErrorListeners,
      )) {
        listener(this, errors, cause);
      }
    },
    notifyListeners: notifyListeners,
  );
  _aggregateCoordinator = FdcDataSetAggregateCoordinator();
  _cursorCoordinator = FdcDataSetCursorCoordinator(
    ensureOpen: _ensureOpen,
    readRecordCount: () => recordCount,
    readViewIndexes: () => _view.viewIndexes,
    resolveActiveEdit: _tryResolveEditForRecordsetChange,
    readCurrentRecordId: () => _currentRecordRaw?.id,
    runOperation: ({required operation, required recordId, required body}) =>
        _errorController.runOperation<void>(
          operation: operation,
          recordId: recordId,
          body: body,
        ),
    beforeScroll: (previousRecordNumber, targetRecordNumber) {
      for (final guard in List<void Function()>.of(
        _internalBeforeScrollGuards.values,
      )) {
        guard();
      }
      _beforeScroll?.call(this, previousRecordNumber, targetRecordNumber);
    },
    afterScroll: (previousRecordNumber, currentRecordNumber) =>
        _afterScroll?.call(this, previousRecordNumber, currentRecordNumber),
    notifyListeners: notifyListeners,
  );
  _recordViewCoordinator = FdcDataSetRecordViewCoordinator(
    recordStore: _recordStore,
    view: _view,
    cursor: _cursorCoordinator,
    readRecordMapper: () => _schemaCoordinator.recordMapper,
    rebuildView: ({preserveRecordId, required notify}) =>
        _rebuildView(preserveRecordId: preserveRecordId, notify: notify),
    beforeAppendRows: () {
      _bumpDataRevision(adapterQueryChanged: false);
      _view.clearComparableValueCache();
    },
    beforeReplaceRows: (adapterQueryChanged) {
      _applyCoordinator.clearPendingImmediateDeletes();
      _bumpDataRevision(adapterQueryChanged: adapterQueryChanged);
      _view.clearComparableValueCache();
      _clearRetainedVisibleRecords();
    },
    beforeDiscardRecord: (record) {
      if (record.selected) {
        _selectionCoordinator.syncSelectionKeyForRecord(record, false);
      }
      _bumpDataRevision(adapterQueryChanged: !_paging.enabled);
      _view.clearComparableValueCache();
    },
    clearEditBuffer: ({required invalidateAggregateCache}) =>
        _clearEditBuffer(invalidateAggregateCache: invalidateAggregateCache),
    readDiscardInvalidatesAggregateCache: () => !_paging.enabled,
    readPagingEnabled: () => _paging.enabled,
  );
  _applyCoordinator = FdcDataSetApplyCoordinator(
    updateMode: _updateMode,
    hasUpdates: () => hasUpdates,
    readState: () => _state,
    ensureOpen: _ensureOpen,
    tryPostActiveEdit: _tryPostActiveEdit,
    buildApplyChangeSet: _buildApplyChangeSet,
    applyLocalChanges: _applyLocalChanges,
    beginAdapterApply: _beginAdapterApply,
    captureLifecycleGeneration: _lifecycleCoordinator.captureGeneration,
    isLifecycleCurrent: _isLifecycleCurrent,
    applyAdapterChanges: _applyAdapterChanges,
    completeApplyResult: _completeApplyResult,
    completeApplyException: _completeApplyException,
    readAdapter: () => _adapter,
    exceptionMessage: _errorController.exceptionMessage,
  );
  _editCoordinator = FdcDataSetEditCoordinator(
    readState: () => _state,
    isImmediateApplyRunning: () => _applyCoordinator.isImmediateApplyRunning,
    readPendingImmediatePostRecordId: () =>
        _applyCoordinator.pendingImmediatePostRecordId,
    hasDirtyEdit: () => _hasDirtyEdit,
    ensureWritable: _ensureWritable,
    ensureOpen: _ensureOpen,
    readCurrentRecord: () => _currentRecordRaw,
    clearErrors: () => _errorController.clearErrors(notify: false),
    beforeEdit: () => _beforeEdit?.call(this),
    beginEdit: (record) => _beginEditBuffer(record, insertRecord: false),
    setState: _setState,
    afterEdit: () => _afterEdit?.call(this),
    notifyListeners: notifyListeners,
    runOperation: ({required operation, required recordId, required body}) =>
        _errorController.runOperation<void>(
          operation: operation,
          recordId: recordId,
          body: body,
        ),
    ensureBrowseLikeState: _ensureBrowseLikeState,
    readCurrentRecordId: () => _currentRecordRaw?.id,
    createInsertedRecord: () => _schemaCoordinator.recordMapper
        .createInsertedRecord(recordId: _recordStore.takeNextRecordId()),
    prepareInsert: (_) {
      _bumpDataRevision(adapterQueryChanged: false);
      _view.clearComparableValueCache();
    },
    resolveInsertRawIndex: (target) => target.resolveRawIndex(
      currentIndex: _cursorCoordinator.currentIndex,
      recordCount: _recordStore.length,
      rawIndexForActiveIndex: _recordViewCoordinator.rawIndexForActiveIndex,
    ),
    insertRawRecord: _recordStore.insertRaw,
    activateInsertedRecord: _activateInsertedRecord,
    emitNewRecordDefaults: _emitNewRecordWithDefaults,
    refreshInsertedRecordView: _refreshInsertedRecordView,
    rollbackFailedInsert: _rollbackFailedInsert,
    beforeInsert: () => _beforeInsert?.call(this),
    afterInsert: () => _afterInsert?.call(this),
    ensureDeleteAllowed: () {
      _ensureWritable();
      _ensureOpen();
      if (_state == FdcDataSetState.loading ||
          _state == FdcDataSetState.applyingUpdates) {
        throw StateError('Cannot delete while dataset is busy.');
      }
    },
    beforeDelete: () => _beforeDelete?.call(this),
    afterDelete: () => _afterDelete?.call(this),
    markPendingImmediateDelete: _applyCoordinator.markPendingImmediateDelete,
    markRecordDeleted: (record, oldIndex) {
      _bumpDataRevision(adapterQueryChanged: !_paging.enabled);
      _view.clearComparableValueCache();
      if (record.selected) {
        _selectionCoordinator.syncSelectionKeyForRecord(record, false);
      }
      record.selected = false;
      record.state = FdcRecordState.deleted;
      _clearEditBuffer(invalidateAggregateCache: !_paging.enabled);
      _rebuildViewSelectingNearestRow(oldIndex);
    },
    ensureEditState: _ensureEditState,
    runPostOperation:
        ({required operation, required recordId, required body}) =>
            _errorController.runOperation<void>(
              operation: operation,
              recordId: recordId,
              wrapUnexpected: false,
              preserveValidationException: true,
              body: body,
            ),
    beforePost: () => _beforePost?.call(this),
    calculateCalculatedValues: _applyCalculatedFields,
    validatePost: (record, values) => <FdcValidationError>[
      ..._schemaCoordinator.validator.validateRecord(record, values: values),
      ..._adapterStorageValidationErrors(record, values),
    ],
    publishValidationErrors: (errors) =>
        _errorController.setValidationErrors(errors, notify: true),
    changedIndexesBetween: (record, values) => _schemaCoordinator.fieldWriter
        .changedIndexesBetween(record.valuesSnapshot(), values)
        .toList(growable: false),
    applyPostedValues: (record, values, changedIndexes) {
      for (final index in changedIndexes) {
        record.setValueAt(index, values[index]);
        _invalidateComparableCacheForField(index);
      }
      _bumpDataRevision(invalidateAggregateCache: false);
    },
    resolvePostedRecordState: (record) {
      if (record.state == FdcRecordState.inserted) {
        return;
      }
      record.state = record.changedFieldIndexes().isEmpty
          ? FdcRecordState.unchanged
          : FdcRecordState.modified;
    },
    retainVisibleRecord: _retainVisibleRecord,
    hasAdapter: () => _adapter != null,
    readUpdateMode: () => _updateMode,
    acceptChanges: (record) => record.acceptChanges(),
    clearEditBuffer: ({required invalidateAggregateCache}) =>
        _clearEditBuffer(invalidateAggregateCache: invalidateAggregateCache),
    markPendingImmediatePost: _applyCoordinator.markPendingImmediatePost,
    afterPost: () => _afterPost?.call(this),
    scheduleImmediateApply: _scheduleImmediateApplyUpdates,
    readPagingEnabled: () => _paging.enabled,
    readCurrentIndex: () => _cursorCoordinator.currentIndex,
    discardRecordFromStore: _discardRecordFromStore,
    rebuildView: ({preserveRecordId}) =>
        _rebuildView(preserveRecordId: preserveRecordId, notify: false),
    beforeCancel: () => _beforeCancel?.call(this),
    afterCancel: () => _afterCancel?.call(this),
  );
  _pagingCoordinator = FdcDataSetPagingCoordinator(
    options: _paging,
    openPageCore: _openPage,
  );
  this.paging = FdcDataSetPagingApi._(this);
  selection = FdcDataSetSelectionApi._(this);
  aggregates = FdcDataSetAggregatesApi._(this);
  bookmarks = FdcDataSetBookmarksApi._(this);
  errors = FdcDataSetErrorsApi._(this);
  _queryCoordinator = FdcDataSetQueryCoordinator(
    pagingEnabled: () => _paging.enabled,
    validateSearchFields: _validateSearchFields,
    readSearchState: () => _view.searchState,
    writeSearchState: (state) => _view.searchState = state,
    validateFilterFields: _validateFilterFields,
    readFilters: () => _view.filters,
    writeFilters: (filters) {
      _view.filters
        ..clear()
        ..addAll(filters);
    },
    readFilterContext: () => _view.filterContext,
    writeFilterContext: (context) => _view.filterContext = context,
    retainedVisibleRecordsAreEmpty: () =>
        _view.retainedVisibleRecordIds.isEmpty,
    notifyFilterChanged: _notifyFilterChanged,
    readSorts: () => _view.sorts,
    writeSorts: (sorts) {
      _view.sorts
        ..clear()
        ..addAll(sorts);
    },
    normalizeSorts: _normalizeSorts,
    isCursorAtFirst: () => _cursorCoordinator.isAtFirst,
    resolveActiveEdit: _tryResolveEditForRecordsetChange,
    clearRetainedVisibleRecords: _clearRetainedVisibleRecords,
    invalidateAggregateCache: _invalidateAggregateCache,
    rebuildView: ({required notify, required resetToFirst}) =>
        _rebuildView(notify: notify, resetToFirst: resetToFirst),
    rebuildViewAsync: ({required notify, required resetToFirst}) =>
        _rebuildViewAsync(notify: notify, resetToFirst: resetToFirst),
    openFirstPage: () => _pagingCoordinator.openPage(),
    notifyListeners: notifyListeners,
  );
  _selectionCoordinator = FdcDataSetSelectionCoordinator(
    pagingEnabled: () => _paging.enabled,
    readViewIndexes: () => _view.viewIndexes,
    recordAtRawIndex: _recordStore.atRawIndex,
    readRecords: () => _recordStore.records,
    replaceRecords: (records) => _recordStore.replaceAll(records),
    ensureNextRecordIdAfter: (internalIds) =>
        _recordStore.ensureNextRecordIdAfter(internalIds),
    readFields: () => _fields,
    fieldIndexByNormalizedName: (name) =>
        _schemaCoordinator.fieldIndexByName[name],
    readSelectedFilter: () => _view.filterContext.selected,
    setTotalRecordCount: _pagingCoordinator.setTotalRecordCount,
    recordToMap: (record, {required includeNonPersistent}) =>
        _schemaCoordinator.recordMapper.recordToMap(
          record,
          includeNonPersistent: includeNonPersistent,
        ),
  );
  filter = FdcDataSetFilters(
    canApplyViewOperation: () => _canApplyViewOperation,
    useAsyncViewOperations: () => _paging.enabled,
    readFilters: () => _view.unmodifiableFilters,
    readContext: () => _view.filterContext,
    isQueryConstraintBlocked: () => _view.isQueryConstraintBlocked,
    replaceFilters: _replaceApiFilters,
    replaceFiltersAsync: _replaceApiFiltersAsync,
    replaceFiltersAndSorts: _replaceApiFiltersAndSorts,
    replaceFiltersAndSortsAsync: _replaceApiFiltersAndSortsAsync,
  );
  sort = FdcDataSetSorts(
    canApplyViewOperation: () => _canApplyViewOperation,
    useAsyncViewOperations: () => _paging.enabled,
    readSorts: () => _view.unmodifiableSorts,
    normalizeSorts: _normalizeSorts,
    replaceSorts: _replaceApiSorts,
    replaceSortsAsync: _replaceApiSortsAsync,
  );
  search = FdcDataSetSearchApi.internal(
    readState: () => _view.currentSearchState,
    applySearch: _applySearch,
    clearSearch: _clearSearch,
  );
  _rebuildView(notify: false);
}