77 * - Subscription barrel file
88 */
99import { generateSubscriptionsBarrel } from '../../core/codegen/barrel' ;
10+ import { generate } from '../../core/codegen/index' ;
1011import {
1112 generateAllSubscriptionHooks ,
1213 generateConnectionStateHook ,
@@ -42,6 +43,7 @@ function createTable(partial: Partial<Table> & { name: string }): Table {
4243 query : partial . query ,
4344 inflection : partial . inflection ,
4445 constraints : partial . constraints ,
46+ smartTags : partial . smartTags ,
4547 } ;
4648}
4749
@@ -63,6 +65,25 @@ const contactTable = createTable({
6365 } ,
6466} ) ;
6567
68+ const contactTableWithRealtime = createTable ( {
69+ name : 'Contact' ,
70+ fields : [
71+ { name : 'id' , type : fieldTypes . uuid } ,
72+ { name : 'firstName' , type : fieldTypes . string } ,
73+ { name : 'lastName' , type : fieldTypes . string } ,
74+ { name : 'email' , type : fieldTypes . string } ,
75+ { name : 'createdAt' , type : fieldTypes . datetime } ,
76+ ] ,
77+ query : {
78+ all : 'contacts' ,
79+ one : 'contact' ,
80+ create : 'createContact' ,
81+ update : 'updateContact' ,
82+ delete : 'deleteContact' ,
83+ } ,
84+ smartTags : { '@realtime' : true } ,
85+ } ) ;
86+
6687const projectTable = createTable ( {
6788 name : 'Project' ,
6889 fields : [
@@ -80,6 +101,24 @@ const projectTable = createTable({
80101 } ,
81102} ) ;
82103
104+ const projectTableWithRealtime = createTable ( {
105+ name : 'Project' ,
106+ fields : [
107+ { name : 'id' , type : fieldTypes . uuid } ,
108+ { name : 'name' , type : fieldTypes . string } ,
109+ { name : 'active' , type : fieldTypes . boolean } ,
110+ { name : 'createdAt' , type : fieldTypes . datetime } ,
111+ ] ,
112+ query : {
113+ all : 'projects' ,
114+ one : 'project' ,
115+ create : 'createProject' ,
116+ update : 'updateProject' ,
117+ delete : 'deleteProject' ,
118+ } ,
119+ smartTags : { '@realtime' : true } ,
120+ } ) ;
121+
83122describe ( 'Subscription naming utils' , ( ) => {
84123 it ( 'generates subscription hook name' , ( ) => {
85124 expect ( getSubscriptionHookName ( contactTable ) ) . toBe (
@@ -243,3 +282,67 @@ describe('Subscription Barrel Generator', () => {
243282 expect ( result ) . toContain ( './useProjectSubscription' ) ;
244283 } ) ;
245284} ) ;
285+
286+ describe ( 'Smart Tag Gating' , ( ) => {
287+ const minConfig = {
288+ tables : { include : [ ] , exclude : [ ] , systemExclude : [ ] } ,
289+ queries : { include : [ ] , exclude : [ ] , systemExclude : [ ] } ,
290+ mutations : { include : [ ] , exclude : [ ] , systemExclude : [ ] } ,
291+ codegen : { skipQueryField : false } ,
292+ reactQuery : true ,
293+ } as any ;
294+
295+ it ( 'does not generate subscription hooks when no tables have @realtime' , ( ) => {
296+ const result = generate ( {
297+ tables : [ contactTable , projectTable ] ,
298+ config : minConfig ,
299+ } ) ;
300+ expect ( result . stats . subscriptionHooks ) . toBe ( 0 ) ;
301+ const subFiles = result . files . filter ( ( f ) => f . path . startsWith ( 'subscriptions/' ) ) ;
302+ expect ( subFiles ) . toHaveLength ( 0 ) ;
303+ } ) ;
304+
305+ it ( 'generates subscription hooks only for tables with @realtime' , ( ) => {
306+ const result = generate ( {
307+ tables : [ contactTableWithRealtime , projectTable ] ,
308+ config : minConfig ,
309+ } ) ;
310+ expect ( result . stats . subscriptionHooks ) . toBe ( 1 ) ;
311+ const subFiles = result . files . filter ( ( f ) => f . path . startsWith ( 'subscriptions/' ) ) ;
312+ expect ( subFiles . some ( ( f ) => f . path . includes ( 'useContactSubscription' ) ) ) . toBe ( true ) ;
313+ expect ( subFiles . some ( ( f ) => f . path . includes ( 'useProjectSubscription' ) ) ) . toBe ( false ) ;
314+ expect ( subFiles . some ( ( f ) => f . path . includes ( 'useConnectionState' ) ) ) . toBe ( true ) ;
315+ expect ( subFiles . some ( ( f ) => f . path === 'subscriptions/index.ts' ) ) . toBe ( true ) ;
316+ } ) ;
317+
318+ it ( 'generates subscription hooks for all @realtime tables' , ( ) => {
319+ const result = generate ( {
320+ tables : [ contactTableWithRealtime , projectTableWithRealtime ] ,
321+ config : minConfig ,
322+ } ) ;
323+ expect ( result . stats . subscriptionHooks ) . toBe ( 2 ) ;
324+ const subFiles = result . files . filter ( ( f ) => f . path . startsWith ( 'subscriptions/' ) ) ;
325+ expect ( subFiles . some ( ( f ) => f . path . includes ( 'useContactSubscription' ) ) ) . toBe ( true ) ;
326+ expect ( subFiles . some ( ( f ) => f . path . includes ( 'useProjectSubscription' ) ) ) . toBe ( true ) ;
327+ } ) ;
328+
329+ it ( 'does not emit useConnectionState or barrel when no @realtime tables' , ( ) => {
330+ const result = generate ( {
331+ tables : [ contactTable ] ,
332+ config : minConfig ,
333+ } ) ;
334+ const subFiles = result . files . filter ( ( f ) => f . path . startsWith ( 'subscriptions/' ) ) ;
335+ expect ( subFiles ) . toHaveLength ( 0 ) ;
336+ const mainBarrel = result . files . find ( ( f ) => f . path === 'index.ts' ) ;
337+ expect ( mainBarrel ?. content ) . not . toContain ( './subscriptions' ) ;
338+ } ) ;
339+
340+ it ( 'emits subscriptions barrel in main index when @realtime tables exist' , ( ) => {
341+ const result = generate ( {
342+ tables : [ contactTableWithRealtime ] ,
343+ config : minConfig ,
344+ } ) ;
345+ const mainBarrel = result . files . find ( ( f ) => f . path === 'index.ts' ) ;
346+ expect ( mainBarrel ?. content ) . toContain ( './subscriptions' ) ;
347+ } ) ;
348+ } ) ;
0 commit comments