@@ -739,7 +739,7 @@ class DeclarativeDatabase {
739739 final serializedValues = _serializeValuesForTable (tableName, values);
740740
741741 final systemId = await _insert (tableName, serializedValues, now);
742- await dirtyRowStore? .add (tableName, systemId, now);
742+ await dirtyRowStore? .add (tableName, systemId, now, true ); // Full row for new inserts
743743
744744 // Notify streaming queries of the change
745745 await _streamManager.notifyTableChanged (tableName);
@@ -766,6 +766,44 @@ class DeclarativeDatabase {
766766 if (valuesToInsert['system_created_at' ] == null ) {
767767 valuesToInsert['system_created_at' ] = hlc.toString ();
768768 }
769+ // Mark as local origin (created by client)
770+ if (valuesToInsert['system_is_local_origin' ] == null ) {
771+ valuesToInsert['system_is_local_origin' ] = 1 ;
772+ }
773+
774+ for (final col in tableDef.columns) {
775+ if (col.isLww) {
776+ valuesToInsert['${col .name }__hlc' ] = hlc.toString ();
777+ }
778+ }
779+
780+ await _db.insert (tableName, valuesToInsert);
781+
782+ return valuesToInsert['system_id' ]! as String ;
783+ }
784+
785+ /// Internal method for inserting rows from server during bulkLoad
786+ /// Marks the row as non-local origin (came from server)
787+ Future <String > _insertFromServer (
788+ String tableName, Map <String , Object ?> values, Hlc hlc) async {
789+ final tableDef = _getTableDefinition (tableName);
790+
791+ // Convert FilesetField values to database strings
792+ final convertedValues = _convertFilesetFieldsToValues (tableName, values);
793+
794+ // Apply default values for missing columns
795+ final valuesToInsert = _applyDefaultValues (tableName, convertedValues);
796+
797+ // Add system columns
798+ valuesToInsert['system_version' ] = hlc.toString ();
799+ if (valuesToInsert['system_id' ] == null ) {
800+ valuesToInsert['system_id' ] = Uuid ().v4 ();
801+ }
802+ if (valuesToInsert['system_created_at' ] == null ) {
803+ valuesToInsert['system_created_at' ] = hlc.toString ();
804+ }
805+ // Mark as server origin (not created locally)
806+ valuesToInsert['system_is_local_origin' ] = 0 ;
769807
770808 for (final col in tableDef.columns) {
771809 if (col.isLww) {
@@ -793,7 +831,7 @@ class DeclarativeDatabase {
793831 return await DbExceptionWrapper .wrapUpdate (() async {
794832 final rowsToUpdate = await query (
795833 (q) {
796- q.from (tableName).select ('system_id' );
834+ q.from (tableName).select ('system_id, system_is_local_origin ' );
797835 if (where != null ) {
798836 q.where (RawSqlWhereClause (where, whereArgs));
799837 }
@@ -814,8 +852,9 @@ class DeclarativeDatabase {
814852
815853 if (result > 0 ) {
816854 for (final row in rowsToUpdate) {
855+ final isLocalOrigin = row.getValue <int >('system_is_local_origin' ) == 1 ;
817856 await dirtyRowStore? .add (
818- tableName, row.getValue <String >('system_id' )! , now);
857+ tableName, row.getValue <String >('system_id' )! , now, isLocalOrigin );
819858 }
820859 // Notify streaming queries of the change
821860 await _streamManager.notifyTableChanged (tableName);
@@ -906,7 +945,7 @@ class DeclarativeDatabase {
906945
907946 final rowsToDelete = await query (
908947 (q) {
909- q.from (tableName).select ('system_id' );
948+ q.from (tableName).select ('system_id, system_is_local_origin ' );
910949 if (where != null ) {
911950 q.where (RawSqlWhereClause (where, whereArgs));
912951 }
@@ -922,8 +961,9 @@ class DeclarativeDatabase {
922961 if (result > 0 ) {
923962 final now = hlcClock.now ();
924963 for (final row in rowsToDelete) {
964+ final isLocalOrigin = row.getValue <int >('system_is_local_origin' ) == 1 ;
925965 await dirtyRowStore? .add (
926- tableName, row.getValue <String >('system_id' )! , now);
966+ tableName, row.getValue <String >('system_id' )! , now, isLocalOrigin );
927967 }
928968 // Notify streaming queries of the change
929969 await _streamManager.notifyTableChanged (tableName);
@@ -1040,9 +1080,11 @@ class DeclarativeDatabase {
10401080 /// - If a local row with the same `system_id` exists, it's an UPDATE.
10411081 /// - LWW columns are only updated if the incoming HLC is newer.
10421082 /// - Regular columns are always updated.
1043- /// - If no local row exists, it's an INSERT.
1083+ /// - The `system_is_local_origin` flag is preserved (not overwritten).
1084+ /// - If no local row exists, it's an INSERT marked as server origin.
10441085 ///
1045- /// Rows processed by this method are NOT marked as dirty.
1086+ /// Rows processed by this method are NOT marked as dirty, as they represent
1087+ /// data coming from the server rather than local changes to be synchronized.
10461088 Future <void > bulkLoad (
10471089 String tableName, List <Map <String , Object ?>> rows) async {
10481090 final tableDef = _getTableDefinition (tableName);
@@ -1071,7 +1113,7 @@ class DeclarativeDatabase {
10711113
10721114 for (final entry in row.entries) {
10731115 final colName = entry.key;
1074- if (pkColumns.contains (colName) || colName.endsWith ('__hlc' )) {
1116+ if (pkColumns.contains (colName) || colName.endsWith ('__hlc' ) || colName == 'system_is_local_origin' ) {
10751117 continue ;
10761118 }
10771119
@@ -1111,8 +1153,8 @@ class DeclarativeDatabase {
11111153 );
11121154 }
11131155 } else {
1114- // INSERT logic
1115- await _insert (tableName, row, hlcClock.now ());
1156+ // INSERT logic - mark as server origin
1157+ await _insertFromServer (tableName, row, hlcClock.now ());
11161158 }
11171159 }
11181160
0 commit comments