diff --git a/.changeset/heavy-shirts-chew.md b/.changeset/heavy-shirts-chew.md new file mode 100644 index 000000000..9bcb5e662 --- /dev/null +++ b/.changeset/heavy-shirts-chew.md @@ -0,0 +1,5 @@ +--- +'@powersync/service-core': patch +--- + +Improved sync rules storage cached parsed sync rules, accommodating different parsing options where necessary. diff --git a/packages/service-core/src/storage/mongo/MongoSyncBucketStorage.ts b/packages/service-core/src/storage/mongo/MongoSyncBucketStorage.ts index 93fb87728..72e007714 100644 --- a/packages/service-core/src/storage/mongo/MongoSyncBucketStorage.ts +++ b/packages/service-core/src/storage/mongo/MongoSyncBucketStorage.ts @@ -9,13 +9,13 @@ import * as util from '../../util/util-index.js'; import { BucketDataBatchOptions, BucketStorageBatch, - ReplicationCheckpoint, CompactOptions, DEFAULT_DOCUMENT_BATCH_LIMIT, DEFAULT_DOCUMENT_CHUNK_LIMIT_BYTES, FlushedResult, ParseSyncRulesOptions, PersistedSyncRulesContent, + ReplicationCheckpoint, ResolveTableOptions, ResolveTableResult, StartBatchOptions, @@ -53,7 +53,7 @@ export class MongoSyncBucketStorage } }); - private parsedSyncRulesCache: SqlSyncRules | undefined; + private parsedSyncRulesCache: {parsed: SqlSyncRules, options: ParseSyncRulesOptions} | undefined; private writeCheckpointAPI: WriteCheckpointAPI; constructor( @@ -104,8 +104,16 @@ export class MongoSyncBucketStorage } getParsedSyncRules(options: ParseSyncRulesOptions): SqlSyncRules { - this.parsedSyncRulesCache ??= this.sync_rules.parsed(options).sync_rules; - return this.parsedSyncRulesCache; + const {parsed, options: cachedOptions} = this.parsedSyncRulesCache ?? {}; + /** + * Check if the cached sync rules, if present, had the same options. + * Parse sync rules if the options are different or if there is no cached value. + */ + if (!parsed || options.defaultSchema != cachedOptions?.defaultSchema ) { + this.parsedSyncRulesCache = {parsed: this.sync_rules.parsed(options).sync_rules, options}; + } + + return this.parsedSyncRulesCache!.parsed; } async getCheckpoint(): Promise { diff --git a/packages/service-core/test/src/data_storage.test.ts b/packages/service-core/test/src/data_storage.test.ts index 776043b03..df8249b6a 100644 --- a/packages/service-core/test/src/data_storage.test.ts +++ b/packages/service-core/test/src/data_storage.test.ts @@ -1,4 +1,5 @@ import { BucketDataBatchOptions, SaveOperationTag } from '@/storage/BucketStorage.js'; +import { getUuidReplicaIdentityBson } from '@/util/util-index.js'; import { RequestParameters } from '@powersync/service-sync-rules'; import { describe, expect, test } from 'vitest'; import { fromAsync, oneFromAsync } from './stream_utils.js'; @@ -13,7 +14,6 @@ import { StorageFactory, testRules } from './util.js'; -import { getUuidReplicaIdentityBson } from '@/util/util-index.js'; const TEST_TABLE = makeTestTable('test', ['id']); @@ -1460,4 +1460,40 @@ bucket_definitions: replication_size_bytes: 0 }); }); + + test('invalidate cached parsed sync rules', async () => { + const sync_rules_content = testRules( + ` +bucket_definitions: + by_workspace: + parameters: + - SELECT id as workspace_id FROM workspace WHERE + workspace."userId" = token_parameters.user_id + data: [] + ` + ); + + const bucketStorageFactory = await factory(); + const syncBucketStorage = bucketStorageFactory.getInstance(sync_rules_content); + + const parsedSchema1 = syncBucketStorage.getParsedSyncRules({ + defaultSchema: 'public' + }); + + const parsedSchema2 = syncBucketStorage.getParsedSyncRules({ + defaultSchema: 'public' + }); + + // These should be cached, this will be the same instance + expect(parsedSchema2).equals(parsedSchema1); + expect(parsedSchema1.getSourceTables()[0].schema).equals('public'); + + const parsedSchema3 = syncBucketStorage.getParsedSyncRules({ + defaultSchema: 'databasename' + }); + + // The cache should not be used + expect(parsedSchema3).not.equals(parsedSchema2); + expect(parsedSchema3.getSourceTables()[0].schema).equals('databasename'); + }); } diff --git a/packages/service-core/test/src/util.ts b/packages/service-core/test/src/util.ts index 98cd613e2..421879d3c 100644 --- a/packages/service-core/test/src/util.ts +++ b/packages/service-core/test/src/util.ts @@ -62,7 +62,7 @@ export function testRules(content: string): PersistedSyncRulesContent { parsed(options) { return { id: 1, - sync_rules: SqlSyncRules.fromYaml(content, PARSE_OPTIONS), + sync_rules: SqlSyncRules.fromYaml(content, options), slot_name: 'test' }; },