@@ -4,17 +4,14 @@ import { getConnections, seed } from 'graphile-test';
44import { join } from 'path' ;
55import type { PgTestClient } from 'pgsql-test' ;
66
7- import { createLtreeOperatorFactory } from '../plugins/connection-filter-operators' ;
8- import { LtreeExtensionDetectionPlugin } from '../plugins/detect-ltree' ;
9- import { LtreeFolderFieldPlugin } from '../plugins/folder-field' ;
107import { createFolderOperatorFactory } from '../plugins/folder-filter-operators' ;
8+ import { LtreeExtensionDetectionPlugin } from '../plugins/detect-ltree' ;
119import { LtreeCodecPlugin } from '../plugins/ltree-codec' ;
1210
1311interface FileNode {
1412 id : number ;
1513 filename : string ;
1614 path : string ;
17- pathTree : string ;
1815}
1916
2017interface AllFilesResult {
@@ -27,7 +24,6 @@ interface CategoryNode {
2724 id : number ;
2825 name : string ;
2926 treePath : string ;
30- treePathTree : string ;
3127}
3228
3329interface AllCategoriesResult {
@@ -53,12 +49,10 @@ describe('graphile-ltree', () => {
5349 ] ,
5450 plugins : [
5551 LtreeExtensionDetectionPlugin ,
56- LtreeCodecPlugin ,
57- LtreeFolderFieldPlugin
52+ LtreeCodecPlugin
5853 ] ,
5954 schema : {
6055 connectionFilterOperatorFactories : [
61- createLtreeOperatorFactory ( ) ,
6256 createFolderOperatorFactory ( )
6357 ]
6458 }
@@ -101,35 +95,20 @@ describe('graphile-ltree', () => {
10195 await db . afterEach ( ) ;
10296 } ) ;
10397
104- // ─── Field naming ─── ──────────────────────────────────────────────────
98+ // ─── File-path output ──────────────────────────────────────────────────
10599
106- describe ( 'field naming ' , ( ) => {
107- it ( 'renames ltree column to pathTree (dot -delimited) ' , async ( ) => {
100+ describe ( 'file-path output ' , ( ) => {
101+ it ( 'returns path as slash -delimited file path ' , async ( ) => {
108102 const result = await query < AllFilesResult > ( `{
109103 allFiles {
110- nodes { id filename pathTree }
104+ nodes { id filename path }
111105 }
112106 }` ) ;
113107 expect ( result . errors ) . toBeUndefined ( ) ;
114108 const nodes = result . data ! . allFiles . nodes ;
115109 expect ( nodes . length ) . toBe ( 10 ) ;
116110 const docsFile = nodes . find ( n => n . filename === 'contract.pdf' ) ;
117111 expect ( docsFile ) . toBeDefined ( ) ;
118- expect ( docsFile ! . pathTree ) . toBe ( 'projects.alpha.docs' ) ;
119- } ) ;
120-
121- it ( 'exposes path as slash-delimited folder field' , async ( ) => {
122- const result = await query < AllFilesResult > ( `{
123- allFiles {
124- nodes { filename path pathTree }
125- }
126- }` ) ;
127- expect ( result . errors ) . toBeUndefined ( ) ;
128- const docsFile = result . data ! . allFiles . nodes . find (
129- n => n . filename === 'contract.pdf'
130- ) ;
131- expect ( docsFile ) . toBeDefined ( ) ;
132- expect ( docsFile ! . pathTree ) . toBe ( 'projects.alpha.docs' ) ;
133112 expect ( docsFile ! . path ) . toBe ( '/projects/alpha/docs' ) ;
134113 } ) ;
135114
@@ -150,26 +129,25 @@ describe('graphile-ltree', () => {
150129 it ( 'works on other tables with ltree columns' , async ( ) => {
151130 const result = await query < AllCategoriesResult > ( `{
152131 allCategories {
153- nodes { name treePath treePathTree }
132+ nodes { name treePath }
154133 }
155134 }` ) ;
156135 expect ( result . errors ) . toBeUndefined ( ) ;
157136 const laptops = result . data ! . allCategories . nodes . find (
158137 n => n . name === 'Laptops'
159138 ) ;
160139 expect ( laptops ) . toBeDefined ( ) ;
161- expect ( laptops ! . treePathTree ) . toBe ( 'shop.electronics.laptops' ) ;
162140 expect ( laptops ! . treePath ) . toBe ( '/shop/electronics/laptops' ) ;
163141 } ) ;
164142 } ) ;
165143
166- // ─── Raw ltree operators (on pathTree) ────── ──────────────────────────
144+ // ─── Filter operators (slash-delimited input) ──────────────────────────
167145
168- describe ( 'isAncestorOf filter' , ( ) => {
169- it ( 'finds files under a given path ' , async ( ) => {
146+ describe ( 'within filter' , ( ) => {
147+ it ( 'finds files within a folder using slash paths ' , async ( ) => {
170148 const result = await query < AllFilesResult > ( `{
171- allFiles(where: { pathTree : { isAncestorOf : "projects. alpha" } }) {
172- nodes { filename }
149+ allFiles(where: { path : { within : "/ projects/ alpha" } }) {
150+ nodes { filename path }
173151 }
174152 }` ) ;
175153 expect ( result . errors ) . toBeUndefined ( ) ;
@@ -184,37 +162,37 @@ describe('graphile-ltree', () => {
184162
185163 it ( 'includes the exact path itself' , async ( ) => {
186164 const result = await query < AllFilesResult > ( `{
187- allFiles(where: { pathTree : { isAncestorOf : "projects. alpha" } }) {
188- nodes { filename pathTree }
165+ allFiles(where: { path : { within : "/ projects/ alpha" } }) {
166+ nodes { filename path }
189167 }
190168 }` ) ;
191169 expect ( result . errors ) . toBeUndefined ( ) ;
192- const paths = result . data ! . allFiles . nodes . map ( n => n . pathTree ) ;
193- expect ( paths ) . toContain ( 'projects. alpha' ) ;
170+ const paths = result . data ! . allFiles . nodes . map ( n => n . path ) ;
171+ expect ( paths ) . toContain ( '/ projects/ alpha' ) ;
194172 } ) ;
195173 } ) ;
196174
197- describe ( 'isDescendantOf filter' , ( ) => {
198- it ( 'finds ancestors of a given path ' , async ( ) => {
175+ describe ( 'ancestorOf filter' , ( ) => {
176+ it ( 'finds ancestor folders using slash paths ' , async ( ) => {
199177 const result = await query < AllFilesResult > ( `{
200- allFiles(where: { pathTree : { isDescendantOf : "projects. alpha. docs. images" } }) {
201- nodes { filename pathTree }
178+ allFiles(where: { path : { ancestorOf : "/ projects/ alpha/ docs/ images" } }) {
179+ nodes { filename path }
202180 }
203181 }` ) ;
204182 expect ( result . errors ) . toBeUndefined ( ) ;
205- const paths = result . data ! . allFiles . nodes . map ( n => n . pathTree ) ;
206- expect ( paths ) . toContain ( 'projects. alpha. docs. images' ) ;
207- expect ( paths ) . toContain ( 'projects. alpha. docs' ) ;
208- expect ( paths ) . toContain ( 'projects. alpha' ) ;
209- expect ( paths ) . toContain ( 'projects' ) ;
183+ const paths = result . data ! . allFiles . nodes . map ( n => n . path ) ;
184+ expect ( paths ) . toContain ( '/ projects/ alpha/ docs/ images' ) ;
185+ expect ( paths ) . toContain ( '/ projects/ alpha/ docs' ) ;
186+ expect ( paths ) . toContain ( '/ projects/ alpha' ) ;
187+ expect ( paths ) . toContain ( '/ projects' ) ;
210188 } ) ;
211189 } ) ;
212190
213- describe ( 'matchesGlob filter' , ( ) => {
214- it ( 'matches single-level wildcard' , async ( ) => {
191+ describe ( 'glob filter' , ( ) => {
192+ it ( 'matches single-level wildcard with slash paths ' , async ( ) => {
215193 const result = await query < AllFilesResult > ( `{
216- allFiles(where: { pathTree : { matchesGlob : "projects. *" } }) {
217- nodes { filename pathTree }
194+ allFiles(where: { path : { glob : "/ projects/ *" } }) {
195+ nodes { filename path }
218196 }
219197 }` ) ;
220198 expect ( result . errors ) . toBeUndefined ( ) ;
@@ -224,10 +202,10 @@ describe('graphile-ltree', () => {
224202 expect ( filenames ) . not . toContain ( 'contract.pdf' ) ;
225203 } ) ;
226204
227- it ( 'matches multi-level wildcard' , async ( ) => {
205+ it ( 'matches multi-level wildcard with slash paths ' , async ( ) => {
228206 const result = await query < AllFilesResult > ( `{
229- allFiles(where: { pathTree : { matchesGlob : "projects.*. docs" } }) {
230- nodes { filename pathTree }
207+ allFiles(where: { path : { glob : "/ projects/*/ docs" } }) {
208+ nodes { filename path }
231209 }
232210 }` ) ;
233211 expect ( result . errors ) . toBeUndefined ( ) ;
@@ -238,67 +216,31 @@ describe('graphile-ltree', () => {
238216 } ) ;
239217 } ) ;
240218
241- // ─── Folder operators (slash-path interface, on pathTree) ─────────────
219+ // ─── Slash-to-ltree conversion (round-trip) ─────────────── ─────────────
242220
243- describe ( 'within filter (folder operator) ' , ( ) => {
244- it ( 'finds files within a folder using slash paths ' , async ( ) => {
221+ describe ( 'slash-to-ltree conversion ' , ( ) => {
222+ it ( 'accepts slash paths on input and stores as ltree ' , async ( ) => {
245223 const result = await query < AllFilesResult > ( `{
246- allFiles(where: { pathTree : { within: "/projects/alpha " } }) {
224+ allFiles(where: { path : { within: "/users " } }) {
247225 nodes { filename path }
248226 }
249227 }` ) ;
250228 expect ( result . errors ) . toBeUndefined ( ) ;
251229 const filenames = result . data ! . allFiles . nodes . map ( n => n . filename ) ;
252- expect ( filenames ) . toContain ( 'alpha-spec.pdf' ) ;
253- expect ( filenames ) . toContain ( 'contract.pdf' ) ;
254- expect ( filenames ) . toContain ( 'design.png' ) ;
255- expect ( filenames ) . toContain ( 'budget.xlsx' ) ;
256- expect ( filenames ) . not . toContain ( 'beta-spec.pdf' ) ;
257- expect ( filenames ) . not . toContain ( 'root.txt' ) ;
230+ expect ( filenames ) . toContain ( 'avatar.jpg' ) ;
231+ expect ( filenames ) . toContain ( 'notes.txt' ) ;
258232 } ) ;
259- } ) ;
260233
261- describe ( 'ancestorOf filter (folder operator)' , ( ) => {
262- it ( 'finds ancestor folders using slash paths' , async ( ) => {
234+ it ( 'dot-delimited input still works (backward compat)' , async ( ) => {
263235 const result = await query < AllFilesResult > ( `{
264- allFiles(where: { pathTree: { ancestorOf: "/projects/alpha/docs/images" } }) {
265- nodes { filename path }
266- }
267- }` ) ;
268- expect ( result . errors ) . toBeUndefined ( ) ;
269- const folders = result . data ! . allFiles . nodes . map ( n => n . path ) ;
270- expect ( folders ) . toContain ( '/projects/alpha/docs/images' ) ;
271- expect ( folders ) . toContain ( '/projects/alpha/docs' ) ;
272- expect ( folders ) . toContain ( '/projects/alpha' ) ;
273- expect ( folders ) . toContain ( '/projects' ) ;
274- } ) ;
275- } ) ;
276-
277- describe ( 'glob filter (folder operator)' , ( ) => {
278- it ( 'matches single-level wildcard with slash paths' , async ( ) => {
279- const result = await query < AllFilesResult > ( `{
280- allFiles(where: { pathTree: { glob: "/projects/*" } }) {
236+ allFiles(where: { path: { within: "projects.alpha" } }) {
281237 nodes { filename path }
282238 }
283239 }` ) ;
284240 expect ( result . errors ) . toBeUndefined ( ) ;
285241 const filenames = result . data ! . allFiles . nodes . map ( n => n . filename ) ;
286242 expect ( filenames ) . toContain ( 'alpha-spec.pdf' ) ;
287- expect ( filenames ) . toContain ( 'beta-spec.pdf' ) ;
288- expect ( filenames ) . not . toContain ( 'contract.pdf' ) ;
289- } ) ;
290-
291- it ( 'matches multi-level wildcard with slash paths' , async ( ) => {
292- const result = await query < AllFilesResult > ( `{
293- allFiles(where: { pathTree: { glob: "/projects/*/docs" } }) {
294- nodes { filename path }
295- }
296- }` ) ;
297- expect ( result . errors ) . toBeUndefined ( ) ;
298- const filenames = result . data ! . allFiles . nodes . map ( n => n . filename ) ;
299243 expect ( filenames ) . toContain ( 'contract.pdf' ) ;
300- expect ( filenames ) . toContain ( 'proposal.docx' ) ;
301- expect ( filenames ) . not . toContain ( 'design.png' ) ;
302244 } ) ;
303245 } ) ;
304246} ) ;
0 commit comments