001package gudusoft.gsqlparser.catalog.runtime; 002 003import gudusoft.gsqlparser.catalog.diagnostic.CatalogException; 004 005/** 006 * Reference {@link CatalogProvider} implementation for tests, demos, and the in-memory 007 * fixture path. Backed by an {@link InMemoryCatalogSnapshot}. 008 * 009 * <p>Plan §6 / §7.2. {@link #snapshot(CatalogQuery)} ignores the query's narrowing 010 * options — the in-memory snapshot is fully materialized — and returns the same instance 011 * on every call until {@link #close()} is invoked. {@link #refresh(CatalogQuery)} forwards 012 * to the seed {@link CatalogProviderConfig} when present (the eager case) or returns the 013 * existing snapshot (the test-fixture case).</p> 014 * 015 * <p>Lifecycle: {@link #open(CatalogProviderConfig)} accepts a config carrying a 016 * {@code "snapshot"} property whose value is the {@link CatalogSnapshot} to serve; 017 * alternatively, a snapshot can be installed at construction time via 018 * {@link #InMemoryCatalogProvider(CatalogSnapshot)}.</p> 019 */ 020public final class InMemoryCatalogProvider implements CatalogProvider { 021 022 /** Property key used by {@link #open(CatalogProviderConfig)} to receive the seed snapshot. */ 023 public static final String CONFIG_SNAPSHOT = "snapshot"; 024 025 private static final CatalogProviderId ID = CatalogProviderId.of("in-memory"); 026 027 private CatalogSnapshot snapshot; 028 private boolean open; 029 030 public InMemoryCatalogProvider() { 031 } 032 033 public InMemoryCatalogProvider(CatalogSnapshot snapshot) { 034 this.snapshot = snapshot; 035 } 036 037 @Override 038 public CatalogProviderId id() { 039 return ID; 040 } 041 042 @Override 043 public void open(CatalogProviderConfig config) throws CatalogException { 044 Object seed = config != null ? config.property(CONFIG_SNAPSHOT) : null; 045 if (seed != null) { 046 if (!(seed instanceof CatalogSnapshot)) { 047 throw new CatalogException("InMemoryCatalogProvider.open: '" 048 + CONFIG_SNAPSHOT + "' property must be a CatalogSnapshot"); 049 } 050 this.snapshot = (CatalogSnapshot) seed; 051 } 052 this.open = true; 053 } 054 055 @Override 056 public CatalogSnapshot snapshot(CatalogQuery query) throws CatalogException { 057 if (!open) { 058 throw new CatalogException("InMemoryCatalogProvider must be opened before snapshot()"); 059 } 060 if (snapshot == null) { 061 throw new CatalogException( 062 "InMemoryCatalogProvider has no snapshot installed; pass one via constructor " 063 + "or via CatalogProviderConfig property '" + CONFIG_SNAPSHOT + "'"); 064 } 065 return snapshot; 066 } 067 068 @Override 069 public CatalogSnapshot refresh(CatalogQuery query) throws CatalogException { 070 return snapshot(query); 071 } 072 073 @Override 074 public void close() throws CatalogException { 075 this.open = false; 076 } 077 078 /** ServiceLoader-discoverable factory. */ 079 public static final class Factory implements CatalogProviderFactory { 080 081 public Factory() { 082 // Required no-arg constructor for ServiceLoader. 083 } 084 085 @Override 086 public CatalogProviderId id() { 087 return ID; 088 } 089 090 @Override 091 public CatalogProvider create() { 092 return new InMemoryCatalogProvider(); 093 } 094 } 095}