[{"data":1,"prerenderedAt":4103},["ShallowReactive",2],{"$awS1iSqIE9":3},[4],{"id":5,"title":6,"body":7,"description":28,"extension":4095,"image":4096,"meta":4097,"navigation":203,"path":4098,"published_at":4099,"seo":4100,"stem":4101,"__hash__":4102},"articles/article/infinite-scroll-with-mysql-tree-structures-in-livewire.md","Infinite Scroll with MySQL Tree Structures in Livewire",{"type":8,"value":9,"toc":4088},"minimark",[10,15,19,22,134,137,309,429,439,443,462,469,472,483,487,490,493,497,510,905,918,1445,1448,1459,2020,2033,2501,2783,2792,2795,3836,4071,4075,4081,4084],[11,12,14],"h2",{"id":13},"the-challenge","The Challenge",[16,17,18],"p",{},"My team recently had the task of paginating a MySQL database table with\nself-references, resulting in a tree structure. The requirements included\ndisplaying trees in depth-first order, paginating results with infinite scroll\nso visual representations of parent-child relationships aren't interrupted, and\nallowing efficient node insertion at any level of the tree while rendering new\nnodes instantly.",[16,20,21],{},"I've put together a simple example application to demonstrate the obsicles we\nfound along the way and how we solved them. To follow along, ensure that PHP\n8.4, Composer, and Laravel Installer are installed. Then, run the following\ncommands to create a new Laravel project and initialize the necessary classes:",[23,24,29],"pre",{"className":25,"code":26,"language":27,"meta":28,"style":28},"language-bash shiki shiki-themes gruvbox-dark-soft","composer require -g livewire/installer\nlaravel new infinite-paginate-tree --livewire\ncd infinite-paginate-tree\nphp artisan make:model Node -m\nphp artisan make:livewire Nodes\nphp artisan make:livewire NodesPage\nphp aritsan make:migration create_nodes_table\n","bash","",[30,31,32,52,67,77,95,108,120],"code",{"__ignoreMap":28},[33,34,37,41,45,49],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"s59W0","composer",[33,42,44],{"class":43},"sTqo2"," require",[33,46,48],{"class":47},"ssIPD"," -g",[33,50,51],{"class":43}," livewire/installer\n",[33,53,55,58,61,64],{"class":35,"line":54},2,[33,56,57],{"class":39},"laravel",[33,59,60],{"class":43}," new",[33,62,63],{"class":43}," infinite-paginate-tree",[33,65,66],{"class":47}," --livewire\n",[33,68,70,74],{"class":35,"line":69},3,[33,71,73],{"class":72},"sG605","cd",[33,75,76],{"class":43}," infinite-paginate-tree\n",[33,78,80,83,86,89,92],{"class":35,"line":79},4,[33,81,82],{"class":39},"php",[33,84,85],{"class":43}," artisan",[33,87,88],{"class":43}," make:model",[33,90,91],{"class":43}," Node",[33,93,94],{"class":47}," -m\n",[33,96,98,100,102,105],{"class":35,"line":97},5,[33,99,82],{"class":39},[33,101,85],{"class":43},[33,103,104],{"class":43}," make:livewire",[33,106,107],{"class":43}," Nodes\n",[33,109,111,113,115,117],{"class":35,"line":110},6,[33,112,82],{"class":39},[33,114,85],{"class":43},[33,116,104],{"class":43},[33,118,119],{"class":43}," NodesPage\n",[33,121,123,125,128,131],{"class":35,"line":122},7,[33,124,82],{"class":39},[33,126,127],{"class":43}," aritsan",[33,129,130],{"class":43}," make:migration",[33,132,133],{"class":43}," create_nodes_table\n",[16,135,136],{},"From there, I simplified the app layout to remove the need for user\nauthentication. And I modified the routes to provide a single route to the nodes\ncomponent.",[23,138,142],{"className":139,"code":140,"filename":141,"language":82,"meta":28,"style":28},"language-php shiki shiki-themes gruvbox-dark-soft","\u003C!DOCTYPE html>\n\u003Chtml lang=\"{{ str_replace('_', '-', app()->getLocale()) }}\" class=\"dark\">\n\n\u003Chead>\n    @include('partials.head')\n\u003C/head>\n\n\u003Cbody class=\"min-h-screen bg-white antialiased dark:bg-linear-to-b dark:from-neutral-950 dark:to-neutral-900\">\n    {{ $slot }}\n\u003C/body>\n\n\u003C/html>\n","resources/views/components/layouts/app.blade.php",[30,143,144,163,199,205,214,236,245,249,270,286,295,300],{"__ignoreMap":28},[33,145,146,150,154,157,160],{"class":35,"line":36},[33,147,149],{"class":148},"sM2RB","\u003C",[33,151,153],{"class":152},"sBQf5","!",[33,155,156],{"class":47},"DOCTYPE",[33,158,159],{"class":47}," html",[33,161,162],{"class":148},">\n",[33,164,165,167,170,173,176,180,183,185,188,190,192,195,197],{"class":35,"line":54},[33,166,149],{"class":148},[33,168,169],{"class":47},"html",[33,171,172],{"class":47}," lang",[33,174,175],{"class":148},"=",[33,177,179],{"class":178},"svnLg","\"",[33,181,182],{"class":43},"{{ str_replace('_', '-', app()->getLocale()) }}",[33,184,179],{"class":178},[33,186,187],{"class":72}," class",[33,189,175],{"class":148},[33,191,179],{"class":178},[33,193,194],{"class":43},"dark",[33,196,179],{"class":178},[33,198,162],{"class":148},[33,200,201],{"class":35,"line":69},[33,202,204],{"emptyLinePlaceholder":203},true,"\n",[33,206,207,209,212],{"class":35,"line":79},[33,208,149],{"class":148},[33,210,211],{"class":47},"head",[33,213,162],{"class":148},[33,215,216,219,222,225,228,231,233],{"class":35,"line":97},[33,217,218],{"class":148},"    @",[33,220,221],{"class":152},"include",[33,223,224],{"class":178},"(",[33,226,227],{"class":178},"'",[33,229,230],{"class":43},"partials.head",[33,232,227],{"class":178},[33,234,235],{"class":178},")\n",[33,237,238,241,243],{"class":35,"line":110},[33,239,240],{"class":148},"\u003C/",[33,242,211],{"class":47},[33,244,162],{"class":148},[33,246,247],{"class":35,"line":122},[33,248,204],{"emptyLinePlaceholder":203},[33,250,252,254,257,259,261,263,266,268],{"class":35,"line":251},8,[33,253,149],{"class":148},[33,255,256],{"class":47},"body",[33,258,187],{"class":72},[33,260,175],{"class":148},[33,262,179],{"class":178},[33,264,265],{"class":43},"min-h-screen bg-white antialiased dark:bg-linear-to-b dark:from-neutral-950 dark:to-neutral-900",[33,267,179],{"class":178},[33,269,162],{"class":148},[33,271,273,276,279,283],{"class":35,"line":272},9,[33,274,275],{"class":178},"    {{",[33,277,278],{"class":178}," $",[33,280,282],{"class":281},"sMWUE","slot",[33,284,285],{"class":178}," }}\n",[33,287,289,291,293],{"class":35,"line":288},10,[33,290,240],{"class":148},[33,292,256],{"class":47},[33,294,162],{"class":148},[33,296,298],{"class":35,"line":297},11,[33,299,204],{"emptyLinePlaceholder":203},[33,301,303,305,307],{"class":35,"line":302},12,[33,304,240],{"class":148},[33,306,169],{"class":47},[33,308,162],{"class":148},[23,310,313],{"className":139,"code":311,"filename":312,"language":82,"meta":28,"style":28},"\u003C?php\n\nuse App\\Livewire\\Nodes;\nuse Illuminate\\Support\\Facades\\Route;\n\nRoute::get('/', Nodes::class)->name('home');\n","routes/web.php",[30,314,315,323,327,350,374,378],{"__ignoreMap":28},[33,316,317,320],{"class":35,"line":36},[33,318,319],{"class":148},"\u003C?",[33,321,322],{"class":47},"php\n",[33,324,325],{"class":35,"line":54},[33,326,204],{"emptyLinePlaceholder":203},[33,328,329,332,336,339,342,344,347],{"class":35,"line":69},[33,330,331],{"class":152},"use",[33,333,335],{"class":334},"sM0OT"," App",[33,337,338],{"class":178},"\\",[33,340,341],{"class":334},"Livewire",[33,343,338],{"class":178},[33,345,346],{"class":334},"Nodes",[33,348,349],{"class":178},";\n",[33,351,352,354,357,359,362,364,367,369,372],{"class":35,"line":79},[33,353,331],{"class":152},[33,355,356],{"class":334}," Illuminate",[33,358,338],{"class":178},[33,360,361],{"class":334},"Support",[33,363,338],{"class":178},[33,365,366],{"class":334},"Facades",[33,368,338],{"class":178},[33,370,371],{"class":334},"Route",[33,373,349],{"class":178},[33,375,376],{"class":35,"line":97},[33,377,204],{"emptyLinePlaceholder":203},[33,379,380,382,385,388,390,392,395,397,400,403,405,408,411,414,417,419,421,424,426],{"class":35,"line":110},[33,381,371],{"class":334},[33,383,384],{"class":148},"::",[33,386,387],{"class":39},"get",[33,389,224],{"class":178},[33,391,227],{"class":178},[33,393,394],{"class":43},"/",[33,396,227],{"class":178},[33,398,399],{"class":178},",",[33,401,402],{"class":334}," Nodes",[33,404,384],{"class":148},[33,406,407],{"class":152},"class",[33,409,410],{"class":178},")",[33,412,413],{"class":148},"->",[33,415,416],{"class":39},"name",[33,418,224],{"class":178},[33,420,227],{"class":178},[33,422,423],{"class":43},"home",[33,425,227],{"class":178},[33,427,428],{"class":178},");\n",[16,430,431,432],{},"You can also find the complete code for this example on\n",[433,434,438],"a",{"href":435,"rel":436},"https://github.com/ben-everly/infinite-paginate-tree",[437],"nofollow","GitHub",[11,440,442],{"id":441},"why-mysql-trees-are-tricky","Why MySQL Trees Are Tricky",[16,444,445,446,449,450,453,454,457,458,461],{},"Modeling a tree structure in a relational database is relatively simple. In this\nexample, nodes are stored as rows in a ",[30,447,448],{},"nodes"," table. The edges are represented\nby a (not so) foreign key, ",[30,451,452],{},"parent_id",", that references another row in the same\ntable. You could also represent edges using another table with columns for\n",[30,455,456],{},"parent_node_id"," and ",[30,459,460],{},"child_node_id",", but for our purposes, the former solution\nwas less complex and more efficient.",[16,463,464,465,468],{},"A significant obstacle, however, lies in ordering the nodes correctly to enable\nseamless pagination. Some databases have support for this process, like\nPostgres, which offers the ",[30,466,467],{},"ltree"," type, or MongoDB, which natively supports\ntrees. If you were starting with a clean slate, you might want to start there.\nUnfortunately, the data in my case was already in MySQL, which as of version 8\ndoes not have support for trees. But instead of migrating to a new database, we\ndecided to work around the limitations.",[16,470,471],{},"Your first instinct, as mine was, might be to sort the nodes in application code\nand manually set an index in the database. However, since we allow nodes to be\ninserted at any point in the tree, this would require us to re-index after every\ninsert. This will become a major bottleneck, causing slow writes and potentially\nlocking issues. A better approach is to index with a string containing a \"path\"\nto the node. Each node is indexed relative to its siblings, and then the index\nis prefixed with the indexes of each of its parents to create the path. Since we\naren't reordering, that means a path can be set when a node is created and\ndoesn't need to be updated again.",[16,473,474,475,478,479,482],{},"However, there is still a problem: string-based paths fail to sort integers with\nvarying lengths correctly. For example, ",[30,476,477],{},"/1/2/"," sorts before ",[30,480,481],{},"/1/10/",". To\naddress this, we can pad each part of the path with zeros to ensure equal\nlengths, enabling string comparisons to correctly mimic integer sorting.\nHowever, if the number of nodes in a group exceeds the padding limit, sorting\nbreaks down. For this example we'll just assume each group contains fewer than\n100,000 nodes and pad each part to 5 digits.",[11,484,486],{"id":485},"handling-inserts-and-infinite-pagination-in-livewire","Handling Inserts and Infinite Pagination in Livewire",[16,488,489],{},"Managing and displaying node inserts while preserving infinite scroll\nfunctionality presents another hurdle. The goal is to display new nodes in the\ncorrect order as the user creates them, without needing a full page refresh.\nUsing a limit an offset is problematic because inserting a new node in the\nmiddle of the tree would shift everything after it, meaning we would have to\nupdate every page we've displayed after the insert.",[16,491,492],{},"To solve this, we can instead use cursor pagination with start and end cursors\nfor each page, and let the pages size vary. When a new node is created determine\nif it fits in the existing pages. If it is within the range of a displayed page,\nsimply refresh that page. If it is between two displayed pages then update a\ncursor so that the new node is included in one of the existing pages.",[11,494,496],{"id":495},"implementing-the-solution","Implementing the Solution",[16,498,499,500,502,503,505,506,509],{},"The first step is to create the database table. With the previous explanation,\nimplementing the migration should be straightforward for those familiar with\nLaravel. We create a ",[30,501,448],{}," table with the ",[30,504,452],{}," foreign key and an\nindexed ",[30,507,508],{},"path"," column.",[23,511,514],{"className":139,"code":512,"filename":513,"language":82,"meta":28,"style":28},"\u003C?php\n\nuse App\\Models\\Node;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up(): void\n    {\n        Schema::create('nodes', function (Blueprint $table) {\n            $table->id();\n            $table->foreignIdFor(Node::class, 'parent_id')->nullable()->constrained();\n            $table->string('path')->index();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down(): void\n    {\n        Schema::dropIfExists('nodes');\n    }\n};\n","database/migrations/xxxx_xx_xx_xxxxxx_create_nodes_table.php",[30,515,516,522,526,544,567,589,609,613,628,633,639,644,649,670,676,716,732,777,806,820,826,832,837,842,848,853,869,874,894,899],{"__ignoreMap":28},[33,517,518,520],{"class":35,"line":36},[33,519,319],{"class":148},[33,521,322],{"class":47},[33,523,524],{"class":35,"line":54},[33,525,204],{"emptyLinePlaceholder":203},[33,527,528,530,532,534,537,539,542],{"class":35,"line":69},[33,529,331],{"class":152},[33,531,335],{"class":334},[33,533,338],{"class":178},[33,535,536],{"class":334},"Models",[33,538,338],{"class":178},[33,540,541],{"class":334},"Node",[33,543,349],{"class":178},[33,545,546,548,550,552,555,557,560,562,565],{"class":35,"line":79},[33,547,331],{"class":152},[33,549,356],{"class":334},[33,551,338],{"class":178},[33,553,554],{"class":334},"Database",[33,556,338],{"class":178},[33,558,559],{"class":334},"Migrations",[33,561,338],{"class":178},[33,563,564],{"class":334},"Migration",[33,566,349],{"class":178},[33,568,569,571,573,575,577,579,582,584,587],{"class":35,"line":97},[33,570,331],{"class":152},[33,572,356],{"class":334},[33,574,338],{"class":178},[33,576,554],{"class":334},[33,578,338],{"class":178},[33,580,581],{"class":334},"Schema",[33,583,338],{"class":178},[33,585,586],{"class":334},"Blueprint",[33,588,349],{"class":178},[33,590,591,593,595,597,599,601,603,605,607],{"class":35,"line":110},[33,592,331],{"class":152},[33,594,356],{"class":334},[33,596,338],{"class":178},[33,598,361],{"class":334},[33,600,338],{"class":178},[33,602,366],{"class":334},[33,604,338],{"class":178},[33,606,581],{"class":334},[33,608,349],{"class":178},[33,610,611],{"class":35,"line":122},[33,612,204],{"emptyLinePlaceholder":203},[33,614,615,618,620,622,625],{"class":35,"line":251},[33,616,617],{"class":152},"return",[33,619,60],{"class":152},[33,621,187],{"class":72},[33,623,624],{"class":72}," extends",[33,626,627],{"class":334}," Migration\n",[33,629,630],{"class":35,"line":272},[33,631,632],{"class":178},"{\n",[33,634,635],{"class":35,"line":288},[33,636,638],{"class":637},"s-UKz","    /**\n",[33,640,641],{"class":35,"line":297},[33,642,643],{"class":637},"     * Run the migrations.\n",[33,645,646],{"class":35,"line":302},[33,647,648],{"class":637},"     */\n",[33,650,652,655,658,661,664,667],{"class":35,"line":651},13,[33,653,654],{"class":72},"    public",[33,656,657],{"class":72}," function",[33,659,660],{"class":39}," up",[33,662,663],{"class":178},"()",[33,665,666],{"class":148},":",[33,668,669],{"class":152}," void\n",[33,671,673],{"class":35,"line":672},14,[33,674,675],{"class":178},"    {\n",[33,677,679,682,684,687,689,691,693,695,697,699,702,705,708,711,713],{"class":35,"line":678},15,[33,680,681],{"class":334},"        Schema",[33,683,384],{"class":148},[33,685,686],{"class":39},"create",[33,688,224],{"class":178},[33,690,227],{"class":178},[33,692,448],{"class":43},[33,694,227],{"class":178},[33,696,399],{"class":178},[33,698,657],{"class":72},[33,700,701],{"class":178}," (",[33,703,704],{"class":334},"Blueprint ",[33,706,707],{"class":178},"$",[33,709,710],{"class":281},"table",[33,712,410],{"class":178},[33,714,715],{"class":178}," {\n",[33,717,719,722,724,726,729],{"class":35,"line":718},16,[33,720,721],{"class":178},"            $",[33,723,710],{"class":281},[33,725,413],{"class":148},[33,727,728],{"class":39},"id",[33,730,731],{"class":178},"();\n",[33,733,735,737,739,741,744,746,748,750,752,754,757,759,761,763,765,768,770,772,775],{"class":35,"line":734},17,[33,736,721],{"class":178},[33,738,710],{"class":281},[33,740,413],{"class":148},[33,742,743],{"class":39},"foreignIdFor",[33,745,224],{"class":178},[33,747,541],{"class":334},[33,749,384],{"class":148},[33,751,407],{"class":152},[33,753,399],{"class":178},[33,755,756],{"class":178}," '",[33,758,452],{"class":43},[33,760,227],{"class":178},[33,762,410],{"class":178},[33,764,413],{"class":148},[33,766,767],{"class":39},"nullable",[33,769,663],{"class":178},[33,771,413],{"class":148},[33,773,774],{"class":39},"constrained",[33,776,731],{"class":178},[33,778,780,782,784,786,789,791,793,795,797,799,801,804],{"class":35,"line":779},18,[33,781,721],{"class":178},[33,783,710],{"class":281},[33,785,413],{"class":148},[33,787,788],{"class":39},"string",[33,790,224],{"class":178},[33,792,227],{"class":178},[33,794,508],{"class":43},[33,796,227],{"class":178},[33,798,410],{"class":178},[33,800,413],{"class":148},[33,802,803],{"class":39},"index",[33,805,731],{"class":178},[33,807,809,811,813,815,818],{"class":35,"line":808},19,[33,810,721],{"class":178},[33,812,710],{"class":281},[33,814,413],{"class":148},[33,816,817],{"class":39},"timestamps",[33,819,731],{"class":178},[33,821,823],{"class":35,"line":822},20,[33,824,825],{"class":178},"        });\n",[33,827,829],{"class":35,"line":828},21,[33,830,831],{"class":178},"    }\n",[33,833,835],{"class":35,"line":834},22,[33,836,204],{"emptyLinePlaceholder":203},[33,838,840],{"class":35,"line":839},23,[33,841,638],{"class":637},[33,843,845],{"class":35,"line":844},24,[33,846,847],{"class":637},"     * Reverse the migrations.\n",[33,849,851],{"class":35,"line":850},25,[33,852,648],{"class":637},[33,854,856,858,860,863,865,867],{"class":35,"line":855},26,[33,857,654],{"class":72},[33,859,657],{"class":72},[33,861,862],{"class":39}," down",[33,864,663],{"class":178},[33,866,666],{"class":148},[33,868,669],{"class":152},[33,870,872],{"class":35,"line":871},27,[33,873,675],{"class":178},[33,875,877,879,881,884,886,888,890,892],{"class":35,"line":876},28,[33,878,681],{"class":334},[33,880,384],{"class":148},[33,882,883],{"class":39},"dropIfExists",[33,885,224],{"class":178},[33,887,227],{"class":178},[33,889,448],{"class":43},[33,891,227],{"class":178},[33,893,428],{"class":178},[33,895,897],{"class":35,"line":896},29,[33,898,831],{"class":178},[33,900,902],{"class":35,"line":901},30,[33,903,904],{"class":178},"};\n",[16,906,907,908,910,911,914,915,917],{},"To initialize ",[30,909,508],{},", we'll use the Eloquent ",[30,912,913],{},"creating"," event by finding the\nlast node in the same group and increment the last part of the path. Other than\nthat, the model will make ",[30,916,452],{}," fillable and implement Eloquent\nrelationships.",[23,919,922],{"className":139,"code":920,"filename":921,"language":82,"meta":28,"style":28},"\u003C?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Node extends Model\n{\n    protected $fillable = ['parent_id'];\n\n    public static function boot()\n    {\n        parent::boot();\n\n        static::creating(function (self $node) {\n            $pathIndex = $node->parent\n                ? $node->parent->children()->max('path')\n                : Node::whereNull('parent_id')->max('path');\n            $pathIndex = collect(explode('/', $pathIndex))\n                ->filter()\n                ->last() + 1;\n            $node->path = ($node->parent?->path ?? '/')\n                .str_pad($pathIndex, 5, '0', STR_PAD_LEFT).'/';\n        });\n    }\n\n    public function parent()\n    {\n        return $this->belongsTo(Node::class, 'parent_id');\n    }\n\n    public function children()\n    {\n        return $this->hasMany(Node::class, 'parent_id');\n    }\n}\n","app/Models/Node.php",[30,923,924,930,934,947,951,973,977,988,992,1017,1021,1036,1040,1052,1056,1084,1102,1138,1174,1207,1217,1234,1271,1316,1320,1324,1328,1339,1343,1376,1380,1385,1397,1402,1434,1439],{"__ignoreMap":28},[33,925,926,928],{"class":35,"line":36},[33,927,319],{"class":148},[33,929,322],{"class":47},[33,931,932],{"class":35,"line":54},[33,933,204],{"emptyLinePlaceholder":203},[33,935,936,939,941,943,945],{"class":35,"line":69},[33,937,938],{"class":152},"namespace",[33,940,335],{"class":39},[33,942,338],{"class":178},[33,944,536],{"class":39},[33,946,349],{"class":178},[33,948,949],{"class":35,"line":79},[33,950,204],{"emptyLinePlaceholder":203},[33,952,953,955,957,959,961,963,966,968,971],{"class":35,"line":97},[33,954,331],{"class":152},[33,956,356],{"class":334},[33,958,338],{"class":178},[33,960,554],{"class":334},[33,962,338],{"class":178},[33,964,965],{"class":334},"Eloquent",[33,967,338],{"class":178},[33,969,970],{"class":334},"Model",[33,972,349],{"class":178},[33,974,975],{"class":35,"line":110},[33,976,204],{"emptyLinePlaceholder":203},[33,978,979,981,983,985],{"class":35,"line":122},[33,980,407],{"class":72},[33,982,91],{"class":39},[33,984,624],{"class":72},[33,986,987],{"class":334}," Model\n",[33,989,990],{"class":35,"line":251},[33,991,632],{"class":178},[33,993,994,997,999,1002,1005,1008,1010,1012,1014],{"class":35,"line":272},[33,995,996],{"class":72},"    protected",[33,998,278],{"class":178},[33,1000,1001],{"class":281},"fillable",[33,1003,1004],{"class":148}," =",[33,1006,1007],{"class":178}," [",[33,1009,227],{"class":178},[33,1011,452],{"class":43},[33,1013,227],{"class":178},[33,1015,1016],{"class":178},"];\n",[33,1018,1019],{"class":35,"line":288},[33,1020,204],{"emptyLinePlaceholder":203},[33,1022,1023,1025,1028,1030,1033],{"class":35,"line":297},[33,1024,654],{"class":72},[33,1026,1027],{"class":72}," static",[33,1029,657],{"class":72},[33,1031,1032],{"class":39}," boot",[33,1034,1035],{"class":178},"()\n",[33,1037,1038],{"class":35,"line":302},[33,1039,675],{"class":178},[33,1041,1042,1045,1047,1050],{"class":35,"line":651},[33,1043,1044],{"class":72},"        parent",[33,1046,384],{"class":148},[33,1048,1049],{"class":39},"boot",[33,1051,731],{"class":178},[33,1053,1054],{"class":35,"line":672},[33,1055,204],{"emptyLinePlaceholder":203},[33,1057,1058,1061,1063,1065,1067,1070,1072,1075,1077,1080,1082],{"class":35,"line":678},[33,1059,1060],{"class":72},"        static",[33,1062,384],{"class":148},[33,1064,913],{"class":39},[33,1066,224],{"class":178},[33,1068,1069],{"class":72},"function",[33,1071,701],{"class":178},[33,1073,1074],{"class":72},"self",[33,1076,278],{"class":178},[33,1078,1079],{"class":281},"node",[33,1081,410],{"class":178},[33,1083,715],{"class":178},[33,1085,1086,1088,1091,1093,1095,1097,1099],{"class":35,"line":718},[33,1087,721],{"class":178},[33,1089,1090],{"class":281},"pathIndex",[33,1092,1004],{"class":148},[33,1094,278],{"class":178},[33,1096,1079],{"class":281},[33,1098,413],{"class":148},[33,1100,1101],{"class":281},"parent\n",[33,1103,1104,1107,1109,1111,1113,1116,1118,1121,1123,1125,1128,1130,1132,1134,1136],{"class":35,"line":734},[33,1105,1106],{"class":148},"                ?",[33,1108,278],{"class":178},[33,1110,1079],{"class":281},[33,1112,413],{"class":148},[33,1114,1115],{"class":281},"parent",[33,1117,413],{"class":148},[33,1119,1120],{"class":39},"children",[33,1122,663],{"class":178},[33,1124,413],{"class":148},[33,1126,1127],{"class":39},"max",[33,1129,224],{"class":178},[33,1131,227],{"class":178},[33,1133,508],{"class":43},[33,1135,227],{"class":178},[33,1137,235],{"class":178},[33,1139,1140,1143,1145,1147,1150,1152,1154,1156,1158,1160,1162,1164,1166,1168,1170,1172],{"class":35,"line":779},[33,1141,1142],{"class":148},"                :",[33,1144,91],{"class":334},[33,1146,384],{"class":148},[33,1148,1149],{"class":39},"whereNull",[33,1151,224],{"class":178},[33,1153,227],{"class":178},[33,1155,452],{"class":43},[33,1157,227],{"class":178},[33,1159,410],{"class":178},[33,1161,413],{"class":148},[33,1163,1127],{"class":39},[33,1165,224],{"class":178},[33,1167,227],{"class":178},[33,1169,508],{"class":43},[33,1171,227],{"class":178},[33,1173,428],{"class":178},[33,1175,1176,1178,1180,1182,1185,1187,1190,1192,1194,1196,1198,1200,1202,1204],{"class":35,"line":808},[33,1177,721],{"class":178},[33,1179,1090],{"class":281},[33,1181,1004],{"class":148},[33,1183,1184],{"class":39}," collect",[33,1186,224],{"class":178},[33,1188,1189],{"class":334},"explode",[33,1191,224],{"class":178},[33,1193,227],{"class":178},[33,1195,394],{"class":43},[33,1197,227],{"class":178},[33,1199,399],{"class":178},[33,1201,278],{"class":178},[33,1203,1090],{"class":281},[33,1205,1206],{"class":178},"))\n",[33,1208,1209,1212,1215],{"class":35,"line":822},[33,1210,1211],{"class":148},"                ->",[33,1213,1214],{"class":39},"filter",[33,1216,1035],{"class":178},[33,1218,1219,1221,1224,1226,1229,1232],{"class":35,"line":828},[33,1220,1211],{"class":148},[33,1222,1223],{"class":39},"last",[33,1225,663],{"class":178},[33,1227,1228],{"class":148}," +",[33,1230,1231],{"class":47}," 1",[33,1233,349],{"class":178},[33,1235,1236,1238,1240,1242,1244,1246,1249,1251,1253,1255,1258,1260,1263,1265,1267,1269],{"class":35,"line":834},[33,1237,721],{"class":178},[33,1239,1079],{"class":281},[33,1241,413],{"class":148},[33,1243,508],{"class":281},[33,1245,1004],{"class":148},[33,1247,1248],{"class":178}," ($",[33,1250,1079],{"class":281},[33,1252,413],{"class":148},[33,1254,1115],{"class":281},[33,1256,1257],{"class":148},"?->",[33,1259,508],{"class":281},[33,1261,1262],{"class":148}," ??",[33,1264,756],{"class":178},[33,1266,394],{"class":43},[33,1268,227],{"class":178},[33,1270,235],{"class":178},[33,1272,1273,1276,1279,1282,1284,1286,1289,1291,1293,1296,1298,1300,1303,1305,1308,1310,1312,1314],{"class":35,"line":839},[33,1274,1275],{"class":148},"                .",[33,1277,1278],{"class":334},"str_pad",[33,1280,1281],{"class":178},"($",[33,1283,1090],{"class":281},[33,1285,399],{"class":178},[33,1287,1288],{"class":47}," 5",[33,1290,399],{"class":178},[33,1292,756],{"class":178},[33,1294,1295],{"class":43},"0",[33,1297,227],{"class":178},[33,1299,399],{"class":178},[33,1301,1302],{"class":47}," STR_PAD_LEFT",[33,1304,410],{"class":178},[33,1306,1307],{"class":148},".",[33,1309,227],{"class":178},[33,1311,394],{"class":43},[33,1313,227],{"class":178},[33,1315,349],{"class":178},[33,1317,1318],{"class":35,"line":844},[33,1319,825],{"class":178},[33,1321,1322],{"class":35,"line":850},[33,1323,831],{"class":178},[33,1325,1326],{"class":35,"line":855},[33,1327,204],{"emptyLinePlaceholder":203},[33,1329,1330,1332,1334,1337],{"class":35,"line":871},[33,1331,654],{"class":72},[33,1333,657],{"class":72},[33,1335,1336],{"class":39}," parent",[33,1338,1035],{"class":178},[33,1340,1341],{"class":35,"line":876},[33,1342,675],{"class":178},[33,1344,1345,1348,1350,1353,1355,1358,1360,1362,1364,1366,1368,1370,1372,1374],{"class":35,"line":896},[33,1346,1347],{"class":152},"        return",[33,1349,278],{"class":178},[33,1351,1352],{"class":281},"this",[33,1354,413],{"class":148},[33,1356,1357],{"class":39},"belongsTo",[33,1359,224],{"class":178},[33,1361,541],{"class":334},[33,1363,384],{"class":148},[33,1365,407],{"class":152},[33,1367,399],{"class":178},[33,1369,756],{"class":178},[33,1371,452],{"class":43},[33,1373,227],{"class":178},[33,1375,428],{"class":178},[33,1377,1378],{"class":35,"line":901},[33,1379,831],{"class":178},[33,1381,1383],{"class":35,"line":1382},31,[33,1384,204],{"emptyLinePlaceholder":203},[33,1386,1388,1390,1392,1395],{"class":35,"line":1387},32,[33,1389,654],{"class":72},[33,1391,657],{"class":72},[33,1393,1394],{"class":39}," children",[33,1396,1035],{"class":178},[33,1398,1400],{"class":35,"line":1399},33,[33,1401,675],{"class":178},[33,1403,1405,1407,1409,1411,1413,1416,1418,1420,1422,1424,1426,1428,1430,1432],{"class":35,"line":1404},34,[33,1406,1347],{"class":152},[33,1408,278],{"class":178},[33,1410,1352],{"class":281},[33,1412,413],{"class":148},[33,1414,1415],{"class":39},"hasMany",[33,1417,224],{"class":178},[33,1419,541],{"class":334},[33,1421,384],{"class":148},[33,1423,407],{"class":152},[33,1425,399],{"class":178},[33,1427,756],{"class":178},[33,1429,452],{"class":43},[33,1431,227],{"class":178},[33,1433,428],{"class":178},[33,1435,1437],{"class":35,"line":1436},35,[33,1438,831],{"class":178},[33,1440,1442],{"class":35,"line":1441},36,[33,1443,1444],{"class":178},"}\n",[16,1446,1447],{},"For the UI, we need one component to display a page of nodes, and a second\ncomponent to manage infinite pagination and mount all the page components. We\nwill also use a wireable data class to help the two components communicate.",[16,1449,1450,1451,1454,1455,1458],{},"The primary responsibility of the ",[30,1452,1453],{},"NodesPageData"," class is to persist the\ncursors across requests. It will also store a collection of nodes which do not\nget persisted across requests. Instead, the collection is only used when\ninitially mounting a page. It allows us to pass the nodes between components to\navoid querying the database twice. Finally, a ",[30,1456,1457],{},"key"," property based on the\ncursors will help uniquely identify each page for dispatching events.",[23,1460,1463],{"className":139,"code":1461,"filename":1462,"language":82,"meta":28,"style":28},"\u003C?php\n\nnamespace App\\Livewire;\n\nuse Illuminate\\Support\\Collection;\nuse Livewire\\Wireable;\n\nclass NodesPageData implements Wireable\n{\n    public string $key;\n\n    public function __construct(\n        public string $start_cursor,\n        public string $end_cursor,\n        public ?Collection $nodes = null\n    ) {\n        $this->key = $this->start_cursor.'-'.$this->end_cursor;\n    }\n\n    public function toLivewire(): array\n    {\n        return [\n            'start_cursor' => $this->start_cursor,\n            'end_cursor' => $this->end_cursor,\n        ];\n    }\n\n    public static function fromLivewire($value): static\n    {\n        return new self($value['start_cursor'], $value['end_cursor']);\n    }\n\n    public static function fromNodes(Collection $nodes): static\n    {\n        if ($nodes->isEmpty()) {\n            throw new \\InvalidArgumentException(\n                'Cannot create from an empty collection of nodes.'\n            );\n        }\n\n        $startCursor = $nodes->first()->path;\n        $endCursor = $nodes->last()->path;\n\n        return new self($startCursor, $endCursor, $nodes);\n    }\n}\n","app/Livewire/NodesPageData.php",[30,1464,1465,1471,1475,1487,1491,1508,1522,1526,1539,1543,1556,1560,1572,1587,1600,1619,1626,1668,1672,1676,1692,1696,1703,1725,1745,1750,1754,1758,1781,1785,1825,1829,1833,1858,1862,1881,1896,1908,1914,1920,1925,1952,1978,1983,2010,2015],{"__ignoreMap":28},[33,1466,1467,1469],{"class":35,"line":36},[33,1468,319],{"class":148},[33,1470,322],{"class":47},[33,1472,1473],{"class":35,"line":54},[33,1474,204],{"emptyLinePlaceholder":203},[33,1476,1477,1479,1481,1483,1485],{"class":35,"line":69},[33,1478,938],{"class":152},[33,1480,335],{"class":39},[33,1482,338],{"class":178},[33,1484,341],{"class":39},[33,1486,349],{"class":178},[33,1488,1489],{"class":35,"line":79},[33,1490,204],{"emptyLinePlaceholder":203},[33,1492,1493,1495,1497,1499,1501,1503,1506],{"class":35,"line":97},[33,1494,331],{"class":152},[33,1496,356],{"class":334},[33,1498,338],{"class":178},[33,1500,361],{"class":334},[33,1502,338],{"class":178},[33,1504,1505],{"class":334},"Collection",[33,1507,349],{"class":178},[33,1509,1510,1512,1515,1517,1520],{"class":35,"line":110},[33,1511,331],{"class":152},[33,1513,1514],{"class":334}," Livewire",[33,1516,338],{"class":178},[33,1518,1519],{"class":334},"Wireable",[33,1521,349],{"class":178},[33,1523,1524],{"class":35,"line":122},[33,1525,204],{"emptyLinePlaceholder":203},[33,1527,1528,1530,1533,1536],{"class":35,"line":251},[33,1529,407],{"class":72},[33,1531,1532],{"class":39}," NodesPageData",[33,1534,1535],{"class":72}," implements",[33,1537,1538],{"class":334}," Wireable\n",[33,1540,1541],{"class":35,"line":272},[33,1542,632],{"class":178},[33,1544,1545,1547,1550,1552,1554],{"class":35,"line":288},[33,1546,654],{"class":72},[33,1548,1549],{"class":152}," string",[33,1551,278],{"class":178},[33,1553,1457],{"class":281},[33,1555,349],{"class":178},[33,1557,1558],{"class":35,"line":297},[33,1559,204],{"emptyLinePlaceholder":203},[33,1561,1562,1564,1566,1569],{"class":35,"line":302},[33,1563,654],{"class":72},[33,1565,657],{"class":72},[33,1567,1568],{"class":334}," __construct",[33,1570,1571],{"class":178},"(\n",[33,1573,1574,1577,1579,1581,1584],{"class":35,"line":651},[33,1575,1576],{"class":72},"        public",[33,1578,1549],{"class":152},[33,1580,278],{"class":178},[33,1582,1583],{"class":281},"start_cursor",[33,1585,1586],{"class":178},",\n",[33,1588,1589,1591,1593,1595,1598],{"class":35,"line":672},[33,1590,1576],{"class":72},[33,1592,1549],{"class":152},[33,1594,278],{"class":178},[33,1596,1597],{"class":281},"end_cursor",[33,1599,1586],{"class":178},[33,1601,1602,1604,1607,1610,1612,1614,1616],{"class":35,"line":678},[33,1603,1576],{"class":72},[33,1605,1606],{"class":148}," ?",[33,1608,1609],{"class":334},"Collection ",[33,1611,707],{"class":178},[33,1613,448],{"class":281},[33,1615,1004],{"class":148},[33,1617,1618],{"class":47}," null\n",[33,1620,1621,1624],{"class":35,"line":718},[33,1622,1623],{"class":178},"    )",[33,1625,715],{"class":178},[33,1627,1628,1631,1633,1635,1637,1639,1641,1643,1645,1647,1649,1651,1654,1656,1658,1660,1662,1664,1666],{"class":35,"line":734},[33,1629,1630],{"class":178},"        $",[33,1632,1352],{"class":281},[33,1634,413],{"class":148},[33,1636,1457],{"class":281},[33,1638,1004],{"class":148},[33,1640,278],{"class":178},[33,1642,1352],{"class":281},[33,1644,413],{"class":148},[33,1646,1583],{"class":281},[33,1648,1307],{"class":148},[33,1650,227],{"class":178},[33,1652,1653],{"class":43},"-",[33,1655,227],{"class":178},[33,1657,1307],{"class":148},[33,1659,707],{"class":178},[33,1661,1352],{"class":281},[33,1663,413],{"class":148},[33,1665,1597],{"class":281},[33,1667,349],{"class":178},[33,1669,1670],{"class":35,"line":779},[33,1671,831],{"class":178},[33,1673,1674],{"class":35,"line":808},[33,1675,204],{"emptyLinePlaceholder":203},[33,1677,1678,1680,1682,1685,1687,1689],{"class":35,"line":822},[33,1679,654],{"class":72},[33,1681,657],{"class":72},[33,1683,1684],{"class":39}," toLivewire",[33,1686,663],{"class":178},[33,1688,666],{"class":148},[33,1690,1691],{"class":152}," array\n",[33,1693,1694],{"class":35,"line":828},[33,1695,675],{"class":178},[33,1697,1698,1700],{"class":35,"line":834},[33,1699,1347],{"class":152},[33,1701,1702],{"class":178}," [\n",[33,1704,1705,1708,1710,1712,1715,1717,1719,1721,1723],{"class":35,"line":839},[33,1706,1707],{"class":178},"            '",[33,1709,1583],{"class":43},[33,1711,227],{"class":178},[33,1713,1714],{"class":148}," =>",[33,1716,278],{"class":178},[33,1718,1352],{"class":281},[33,1720,413],{"class":148},[33,1722,1583],{"class":281},[33,1724,1586],{"class":178},[33,1726,1727,1729,1731,1733,1735,1737,1739,1741,1743],{"class":35,"line":844},[33,1728,1707],{"class":178},[33,1730,1597],{"class":43},[33,1732,227],{"class":178},[33,1734,1714],{"class":148},[33,1736,278],{"class":178},[33,1738,1352],{"class":281},[33,1740,413],{"class":148},[33,1742,1597],{"class":281},[33,1744,1586],{"class":178},[33,1746,1747],{"class":35,"line":850},[33,1748,1749],{"class":178},"        ];\n",[33,1751,1752],{"class":35,"line":855},[33,1753,831],{"class":178},[33,1755,1756],{"class":35,"line":871},[33,1757,204],{"emptyLinePlaceholder":203},[33,1759,1760,1762,1764,1766,1769,1771,1774,1776,1778],{"class":35,"line":876},[33,1761,654],{"class":72},[33,1763,1027],{"class":72},[33,1765,657],{"class":72},[33,1767,1768],{"class":39}," fromLivewire",[33,1770,1281],{"class":178},[33,1772,1773],{"class":281},"value",[33,1775,410],{"class":178},[33,1777,666],{"class":148},[33,1779,1780],{"class":72}," static\n",[33,1782,1783],{"class":35,"line":896},[33,1784,675],{"class":178},[33,1786,1787,1789,1791,1794,1796,1798,1801,1803,1805,1807,1810,1812,1814,1816,1818,1820,1822],{"class":35,"line":901},[33,1788,1347],{"class":152},[33,1790,60],{"class":152},[33,1792,1793],{"class":72}," self",[33,1795,1281],{"class":178},[33,1797,1773],{"class":281},[33,1799,1800],{"class":178},"[",[33,1802,227],{"class":178},[33,1804,1583],{"class":43},[33,1806,227],{"class":178},[33,1808,1809],{"class":178},"],",[33,1811,278],{"class":178},[33,1813,1773],{"class":281},[33,1815,1800],{"class":178},[33,1817,227],{"class":178},[33,1819,1597],{"class":43},[33,1821,227],{"class":178},[33,1823,1824],{"class":178},"]);\n",[33,1826,1827],{"class":35,"line":1382},[33,1828,831],{"class":178},[33,1830,1831],{"class":35,"line":1387},[33,1832,204],{"emptyLinePlaceholder":203},[33,1834,1835,1837,1839,1841,1844,1846,1848,1850,1852,1854,1856],{"class":35,"line":1399},[33,1836,654],{"class":72},[33,1838,1027],{"class":72},[33,1840,657],{"class":72},[33,1842,1843],{"class":39}," fromNodes",[33,1845,224],{"class":178},[33,1847,1609],{"class":334},[33,1849,707],{"class":178},[33,1851,448],{"class":281},[33,1853,410],{"class":178},[33,1855,666],{"class":148},[33,1857,1780],{"class":72},[33,1859,1860],{"class":35,"line":1404},[33,1861,675],{"class":178},[33,1863,1864,1867,1869,1871,1873,1876,1879],{"class":35,"line":1436},[33,1865,1866],{"class":152},"        if",[33,1868,1248],{"class":178},[33,1870,448],{"class":281},[33,1872,413],{"class":148},[33,1874,1875],{"class":39},"isEmpty",[33,1877,1878],{"class":178},"())",[33,1880,715],{"class":178},[33,1882,1883,1886,1888,1891,1894],{"class":35,"line":1441},[33,1884,1885],{"class":152},"            throw",[33,1887,60],{"class":152},[33,1889,1890],{"class":178}," \\",[33,1892,1893],{"class":334},"InvalidArgumentException",[33,1895,1571],{"class":178},[33,1897,1899,1902,1905],{"class":35,"line":1898},37,[33,1900,1901],{"class":178},"                '",[33,1903,1904],{"class":43},"Cannot create from an empty collection of nodes.",[33,1906,1907],{"class":178},"'\n",[33,1909,1911],{"class":35,"line":1910},38,[33,1912,1913],{"class":178},"            );\n",[33,1915,1917],{"class":35,"line":1916},39,[33,1918,1919],{"class":178},"        }\n",[33,1921,1923],{"class":35,"line":1922},40,[33,1924,204],{"emptyLinePlaceholder":203},[33,1926,1928,1930,1933,1935,1937,1939,1941,1944,1946,1948,1950],{"class":35,"line":1927},41,[33,1929,1630],{"class":178},[33,1931,1932],{"class":281},"startCursor",[33,1934,1004],{"class":148},[33,1936,278],{"class":178},[33,1938,448],{"class":281},[33,1940,413],{"class":148},[33,1942,1943],{"class":39},"first",[33,1945,663],{"class":178},[33,1947,413],{"class":148},[33,1949,508],{"class":281},[33,1951,349],{"class":178},[33,1953,1955,1957,1960,1962,1964,1966,1968,1970,1972,1974,1976],{"class":35,"line":1954},42,[33,1956,1630],{"class":178},[33,1958,1959],{"class":281},"endCursor",[33,1961,1004],{"class":148},[33,1963,278],{"class":178},[33,1965,448],{"class":281},[33,1967,413],{"class":148},[33,1969,1223],{"class":39},[33,1971,663],{"class":178},[33,1973,413],{"class":148},[33,1975,508],{"class":281},[33,1977,349],{"class":178},[33,1979,1981],{"class":35,"line":1980},43,[33,1982,204],{"emptyLinePlaceholder":203},[33,1984,1986,1988,1990,1992,1994,1996,1998,2000,2002,2004,2006,2008],{"class":35,"line":1985},44,[33,1987,1347],{"class":152},[33,1989,60],{"class":152},[33,1991,1793],{"class":72},[33,1993,1281],{"class":178},[33,1995,1932],{"class":281},[33,1997,399],{"class":178},[33,1999,278],{"class":178},[33,2001,1959],{"class":281},[33,2003,399],{"class":178},[33,2005,278],{"class":178},[33,2007,448],{"class":281},[33,2009,428],{"class":178},[33,2011,2013],{"class":35,"line":2012},45,[33,2014,831],{"class":178},[33,2016,2018],{"class":35,"line":2017},46,[33,2019,1444],{"class":178},[16,2021,2022,2023,2026,2027,2029,2030,2032],{},"The ",[30,2024,2025],{},"NodesPage"," component renders a single page of nodes and handles child\ncreation. It accesses ",[30,2028,1453],{}," to check if nodes have been passed, and if\nnot it uses the cursors to query the database. It renders the nodes with a left\nmargin determined by the nodes 'depth', which is computed by counting the\ndelimiters in its ",[30,2031,508],{},". Lastly, a button allows child node creation, which is\ndelegated to the parent component by dispatching an event.",[23,2034,2037],{"className":139,"code":2035,"filename":2036,"language":82,"meta":28,"style":28},"\u003C?php\n\nnamespace App\\Livewire;\n\nuse App\\Models\\Node;\nuse Illuminate\\Support\\Collection;\nuse Livewire\\Attributes\\Computed;\nuse Livewire\\Attributes\\On;\nuse Livewire\\Component;\n\n#[On(NodesPage::REFRESH_EVENT.'{pageData.key}')]\nclass NodesPage extends Component\n{\n    public const REFRESH_EVENT = 'nodes_page.refresh.';\n\n    public NodesPageData $pageData;\n\n    #[Computed]\n    public function nodes(): Collection\n    {\n        if ($this->pageData->nodes !== null) {\n            return $this->pageData->nodes;\n        }\n\n        return Node::query()\n            ->orderBy('path')\n            ->where('path', '>=', $this->pageData->start_cursor)\n            ->where('path', '\u003C=', $this->pageData->end_cursor)\n            ->get();\n    }\n\n    public function createChild(int $parentId)\n    {\n        $this->dispatch(Nodes::CREATE_NODE_EVENT, $parentId);\n    }\n}\n","app/Livewire/NodesPage.php",[30,2038,2039,2045,2049,2061,2065,2081,2097,2115,2132,2145,2149,2177,2189,2193,2214,2218,2232,2236,2241,2257,2261,2287,2306,2310,2314,2327,2345,2385,2424,2432,2436,2440,2461,2465,2493,2497],{"__ignoreMap":28},[33,2040,2041,2043],{"class":35,"line":36},[33,2042,319],{"class":148},[33,2044,322],{"class":47},[33,2046,2047],{"class":35,"line":54},[33,2048,204],{"emptyLinePlaceholder":203},[33,2050,2051,2053,2055,2057,2059],{"class":35,"line":69},[33,2052,938],{"class":152},[33,2054,335],{"class":39},[33,2056,338],{"class":178},[33,2058,341],{"class":39},[33,2060,349],{"class":178},[33,2062,2063],{"class":35,"line":79},[33,2064,204],{"emptyLinePlaceholder":203},[33,2066,2067,2069,2071,2073,2075,2077,2079],{"class":35,"line":97},[33,2068,331],{"class":152},[33,2070,335],{"class":334},[33,2072,338],{"class":178},[33,2074,536],{"class":334},[33,2076,338],{"class":178},[33,2078,541],{"class":334},[33,2080,349],{"class":178},[33,2082,2083,2085,2087,2089,2091,2093,2095],{"class":35,"line":110},[33,2084,331],{"class":152},[33,2086,356],{"class":334},[33,2088,338],{"class":178},[33,2090,361],{"class":334},[33,2092,338],{"class":178},[33,2094,1505],{"class":334},[33,2096,349],{"class":178},[33,2098,2099,2101,2103,2105,2108,2110,2113],{"class":35,"line":122},[33,2100,331],{"class":152},[33,2102,1514],{"class":334},[33,2104,338],{"class":178},[33,2106,2107],{"class":334},"Attributes",[33,2109,338],{"class":178},[33,2111,2112],{"class":334},"Computed",[33,2114,349],{"class":178},[33,2116,2117,2119,2121,2123,2125,2127,2130],{"class":35,"line":251},[33,2118,331],{"class":152},[33,2120,1514],{"class":334},[33,2122,338],{"class":178},[33,2124,2107],{"class":334},[33,2126,338],{"class":178},[33,2128,2129],{"class":334},"On",[33,2131,349],{"class":178},[33,2133,2134,2136,2138,2140,2143],{"class":35,"line":272},[33,2135,331],{"class":152},[33,2137,1514],{"class":334},[33,2139,338],{"class":178},[33,2141,2142],{"class":334},"Component",[33,2144,349],{"class":178},[33,2146,2147],{"class":35,"line":288},[33,2148,204],{"emptyLinePlaceholder":203},[33,2150,2151,2154,2156,2158,2160,2163,2165,2167,2170,2172,2174],{"class":35,"line":297},[33,2152,2153],{"class":334},"#[On",[33,2155,224],{"class":178},[33,2157,2025],{"class":334},[33,2159,384],{"class":148},[33,2161,2162],{"class":47},"REFRESH_EVENT",[33,2164,1307],{"class":148},[33,2166,227],{"class":178},[33,2168,2169],{"class":43},"{pageData.key}",[33,2171,227],{"class":178},[33,2173,410],{"class":178},[33,2175,2176],{"class":334},"]\n",[33,2178,2179,2181,2184,2186],{"class":35,"line":302},[33,2180,407],{"class":72},[33,2182,2183],{"class":39}," NodesPage",[33,2185,624],{"class":72},[33,2187,2188],{"class":334}," Component\n",[33,2190,2191],{"class":35,"line":651},[33,2192,632],{"class":178},[33,2194,2195,2197,2200,2203,2205,2207,2210,2212],{"class":35,"line":672},[33,2196,654],{"class":72},[33,2198,2199],{"class":72}," const",[33,2201,2202],{"class":47}," REFRESH_EVENT",[33,2204,1004],{"class":148},[33,2206,756],{"class":178},[33,2208,2209],{"class":43},"nodes_page.refresh.",[33,2211,227],{"class":178},[33,2213,349],{"class":178},[33,2215,2216],{"class":35,"line":678},[33,2217,204],{"emptyLinePlaceholder":203},[33,2219,2220,2222,2225,2227,2230],{"class":35,"line":718},[33,2221,654],{"class":72},[33,2223,2224],{"class":334}," NodesPageData ",[33,2226,707],{"class":178},[33,2228,2229],{"class":281},"pageData",[33,2231,349],{"class":178},[33,2233,2234],{"class":35,"line":734},[33,2235,204],{"emptyLinePlaceholder":203},[33,2237,2238],{"class":35,"line":779},[33,2239,2240],{"class":334},"    #[Computed]\n",[33,2242,2243,2245,2247,2250,2252,2254],{"class":35,"line":808},[33,2244,654],{"class":72},[33,2246,657],{"class":72},[33,2248,2249],{"class":39}," nodes",[33,2251,663],{"class":178},[33,2253,666],{"class":148},[33,2255,2256],{"class":334}," Collection\n",[33,2258,2259],{"class":35,"line":822},[33,2260,675],{"class":178},[33,2262,2263,2265,2267,2269,2271,2273,2275,2277,2280,2283,2285],{"class":35,"line":828},[33,2264,1866],{"class":152},[33,2266,1248],{"class":178},[33,2268,1352],{"class":281},[33,2270,413],{"class":148},[33,2272,2229],{"class":281},[33,2274,413],{"class":148},[33,2276,448],{"class":281},[33,2278,2279],{"class":148}," !==",[33,2281,2282],{"class":47}," null",[33,2284,410],{"class":178},[33,2286,715],{"class":178},[33,2288,2289,2292,2294,2296,2298,2300,2302,2304],{"class":35,"line":834},[33,2290,2291],{"class":152},"            return",[33,2293,278],{"class":178},[33,2295,1352],{"class":281},[33,2297,413],{"class":148},[33,2299,2229],{"class":281},[33,2301,413],{"class":148},[33,2303,448],{"class":281},[33,2305,349],{"class":178},[33,2307,2308],{"class":35,"line":839},[33,2309,1919],{"class":178},[33,2311,2312],{"class":35,"line":844},[33,2313,204],{"emptyLinePlaceholder":203},[33,2315,2316,2318,2320,2322,2325],{"class":35,"line":850},[33,2317,1347],{"class":152},[33,2319,91],{"class":334},[33,2321,384],{"class":148},[33,2323,2324],{"class":39},"query",[33,2326,1035],{"class":178},[33,2328,2329,2332,2335,2337,2339,2341,2343],{"class":35,"line":855},[33,2330,2331],{"class":148},"            ->",[33,2333,2334],{"class":39},"orderBy",[33,2336,224],{"class":178},[33,2338,227],{"class":178},[33,2340,508],{"class":43},[33,2342,227],{"class":178},[33,2344,235],{"class":178},[33,2346,2347,2349,2352,2354,2356,2358,2360,2362,2364,2367,2369,2371,2373,2375,2377,2379,2381,2383],{"class":35,"line":871},[33,2348,2331],{"class":148},[33,2350,2351],{"class":39},"where",[33,2353,224],{"class":178},[33,2355,227],{"class":178},[33,2357,508],{"class":43},[33,2359,227],{"class":178},[33,2361,399],{"class":178},[33,2363,756],{"class":178},[33,2365,2366],{"class":43},">=",[33,2368,227],{"class":178},[33,2370,399],{"class":178},[33,2372,278],{"class":178},[33,2374,1352],{"class":281},[33,2376,413],{"class":148},[33,2378,2229],{"class":281},[33,2380,413],{"class":148},[33,2382,1583],{"class":281},[33,2384,235],{"class":178},[33,2386,2387,2389,2391,2393,2395,2397,2399,2401,2403,2406,2408,2410,2412,2414,2416,2418,2420,2422],{"class":35,"line":876},[33,2388,2331],{"class":148},[33,2390,2351],{"class":39},[33,2392,224],{"class":178},[33,2394,227],{"class":178},[33,2396,508],{"class":43},[33,2398,227],{"class":178},[33,2400,399],{"class":178},[33,2402,756],{"class":178},[33,2404,2405],{"class":43},"\u003C=",[33,2407,227],{"class":178},[33,2409,399],{"class":178},[33,2411,278],{"class":178},[33,2413,1352],{"class":281},[33,2415,413],{"class":148},[33,2417,2229],{"class":281},[33,2419,413],{"class":148},[33,2421,1597],{"class":281},[33,2423,235],{"class":178},[33,2425,2426,2428,2430],{"class":35,"line":896},[33,2427,2331],{"class":148},[33,2429,387],{"class":39},[33,2431,731],{"class":178},[33,2433,2434],{"class":35,"line":901},[33,2435,831],{"class":178},[33,2437,2438],{"class":35,"line":1382},[33,2439,204],{"emptyLinePlaceholder":203},[33,2441,2442,2444,2446,2449,2451,2454,2456,2459],{"class":35,"line":1387},[33,2443,654],{"class":72},[33,2445,657],{"class":72},[33,2447,2448],{"class":39}," createChild",[33,2450,224],{"class":178},[33,2452,2453],{"class":152},"int",[33,2455,278],{"class":178},[33,2457,2458],{"class":281},"parentId",[33,2460,235],{"class":178},[33,2462,2463],{"class":35,"line":1399},[33,2464,675],{"class":178},[33,2466,2467,2469,2471,2473,2476,2478,2480,2482,2485,2487,2489,2491],{"class":35,"line":1404},[33,2468,1630],{"class":178},[33,2470,1352],{"class":281},[33,2472,413],{"class":148},[33,2474,2475],{"class":39},"dispatch",[33,2477,224],{"class":178},[33,2479,346],{"class":334},[33,2481,384],{"class":148},[33,2483,2484],{"class":47},"CREATE_NODE_EVENT",[33,2486,399],{"class":178},[33,2488,278],{"class":178},[33,2490,2458],{"class":281},[33,2492,428],{"class":178},[33,2494,2495],{"class":35,"line":1436},[33,2496,831],{"class":178},[33,2498,2499],{"class":35,"line":1441},[33,2500,1444],{"class":178},[23,2502,2505],{"className":139,"code":2503,"filename":2504,"language":82,"meta":28,"style":28},"@php\n    use App\\Livewire\\Nodes;\n@endphp\n\u003Cdiv>\n    @foreach ($this->nodes as $node)\n        @php\n            $depth = substr_count($node->path, '/') - 2;\n        @endphp\n        \u003Cdiv class=\"p-2 my-2 flex gap-2\" style=\"margin-left: {{ $depth * 20 }}px;\">\n            \u003Ch3>Node {{ $node->id }}\u003C/h3>\n            \u003Cbutton class=\"border\" wire:click=\"createChild({{ $node->id }})\">\n                Create Child\n            \u003C/button>\n        \u003C/div>\n    @endforeach\n\u003C/div>\n","resources/views/livewire/nodes-page.blade.php",[30,2506,2507,2514,2531,2538,2547,2571,2578,2616,2622,2661,2694,2742,2750,2759,2768,2775],{"__ignoreMap":28},[33,2508,2509,2512],{"class":35,"line":36},[33,2510,2511],{"class":148},"@",[33,2513,322],{"class":47},[33,2515,2516,2519,2521,2523,2525,2527,2529],{"class":35,"line":54},[33,2517,2518],{"class":152},"    use",[33,2520,335],{"class":334},[33,2522,338],{"class":178},[33,2524,341],{"class":334},[33,2526,338],{"class":178},[33,2528,346],{"class":334},[33,2530,349],{"class":178},[33,2532,2533,2535],{"class":35,"line":69},[33,2534,2511],{"class":148},[33,2536,2537],{"class":47},"endphp\n",[33,2539,2540,2542,2545],{"class":35,"line":79},[33,2541,149],{"class":148},[33,2543,2544],{"class":47},"div",[33,2546,162],{"class":148},[33,2548,2549,2551,2554,2556,2558,2560,2562,2565,2567,2569],{"class":35,"line":97},[33,2550,218],{"class":148},[33,2552,2553],{"class":152},"foreach",[33,2555,1248],{"class":178},[33,2557,1352],{"class":281},[33,2559,413],{"class":148},[33,2561,448],{"class":281},[33,2563,2564],{"class":152}," as",[33,2566,278],{"class":178},[33,2568,1079],{"class":281},[33,2570,235],{"class":178},[33,2572,2573,2576],{"class":35,"line":110},[33,2574,2575],{"class":148},"        @",[33,2577,322],{"class":47},[33,2579,2580,2582,2585,2587,2590,2592,2594,2596,2598,2600,2602,2604,2606,2608,2611,2614],{"class":35,"line":122},[33,2581,721],{"class":178},[33,2583,2584],{"class":281},"depth",[33,2586,1004],{"class":148},[33,2588,2589],{"class":334}," substr_count",[33,2591,1281],{"class":178},[33,2593,1079],{"class":281},[33,2595,413],{"class":148},[33,2597,508],{"class":281},[33,2599,399],{"class":178},[33,2601,756],{"class":178},[33,2603,394],{"class":43},[33,2605,227],{"class":178},[33,2607,410],{"class":178},[33,2609,2610],{"class":148}," -",[33,2612,2613],{"class":47}," 2",[33,2615,349],{"class":178},[33,2617,2618,2620],{"class":35,"line":251},[33,2619,2575],{"class":148},[33,2621,2537],{"class":47},[33,2623,2624,2627,2629,2631,2633,2635,2638,2640,2643,2645,2647,2650,2652,2654,2657,2659],{"class":35,"line":272},[33,2625,2626],{"class":148},"        \u003C",[33,2628,2544],{"class":47},[33,2630,187],{"class":72},[33,2632,175],{"class":148},[33,2634,179],{"class":178},[33,2636,2637],{"class":43},"p-2 my-2 flex gap-2",[33,2639,179],{"class":178},[33,2641,2642],{"class":47}," style",[33,2644,175],{"class":148},[33,2646,179],{"class":178},[33,2648,2649],{"class":43},"margin-left: {{ ",[33,2651,707],{"class":178},[33,2653,2584],{"class":281},[33,2655,2656],{"class":43}," * 20 }}px;",[33,2658,179],{"class":178},[33,2660,162],{"class":148},[33,2662,2663,2666,2669,2672,2674,2677,2679,2681,2683,2685,2688,2690,2692],{"class":35,"line":288},[33,2664,2665],{"class":148},"            \u003C",[33,2667,2668],{"class":47},"h3",[33,2670,2671],{"class":148},">",[33,2673,541],{"class":47},[33,2675,2676],{"class":178}," {{",[33,2678,278],{"class":178},[33,2680,1079],{"class":281},[33,2682,413],{"class":148},[33,2684,728],{"class":281},[33,2686,2687],{"class":178}," }}",[33,2689,240],{"class":148},[33,2691,2668],{"class":47},[33,2693,162],{"class":148},[33,2695,2696,2698,2701,2703,2705,2707,2710,2712,2715,2717,2720,2722,2724,2727,2729,2731,2733,2735,2738,2740],{"class":35,"line":297},[33,2697,2665],{"class":148},[33,2699,2700],{"class":47},"button",[33,2702,187],{"class":72},[33,2704,175],{"class":148},[33,2706,179],{"class":178},[33,2708,2709],{"class":43},"border",[33,2711,179],{"class":178},[33,2713,2714],{"class":47}," wire",[33,2716,666],{"class":178},[33,2718,2719],{"class":47},"click",[33,2721,175],{"class":148},[33,2723,179],{"class":178},[33,2725,2726],{"class":43},"createChild({{ ",[33,2728,707],{"class":178},[33,2730,1079],{"class":281},[33,2732,413],{"class":148},[33,2734,728],{"class":281},[33,2736,2737],{"class":43}," }})",[33,2739,179],{"class":178},[33,2741,162],{"class":148},[33,2743,2744,2747],{"class":35,"line":302},[33,2745,2746],{"class":47},"                Create",[33,2748,2749],{"class":47}," Child\n",[33,2751,2752,2755,2757],{"class":35,"line":651},[33,2753,2754],{"class":148},"            \u003C/",[33,2756,2700],{"class":47},[33,2758,162],{"class":148},[33,2760,2761,2764,2766],{"class":35,"line":672},[33,2762,2763],{"class":148},"        \u003C/",[33,2765,2544],{"class":47},[33,2767,162],{"class":148},[33,2769,2770,2772],{"class":35,"line":678},[33,2771,218],{"class":148},[33,2773,2774],{"class":152},"endforeach\n",[33,2776,2777,2779,2781],{"class":35,"line":718},[33,2778,240],{"class":148},[33,2780,2544],{"class":47},[33,2782,162],{"class":148},[16,2784,2785,2786,2788,2789,2791],{},"The final piece is the ",[30,2787,346],{}," component, which tracks the pages using an array\nof ",[30,2790,1453],{},". When a page is added, it keeps the next cursor as well as a\nflag to indicate if there are more pages to reduce database calls.",[16,2793,2794],{},"The create node method creates nodes, obviously, and then determines how it fits\ninto the existing pages, updating cursors if needed. It also displays the first\npage when the first node is created.",[23,2796,2799],{"className":139,"code":2797,"filename":2798,"language":82,"meta":28,"style":28},"\u003C?php\n\nnamespace App\\Livewire;\n\nuse App\\Models\\Node;\nuse Illuminate\\Pagination\\Cursor;\nuse Illuminate\\Support\\Collection;\nuse Livewire\\Attributes\\On;\nuse Livewire\\Component;\n\nclass Nodes extends Component\n{\n    public const CREATE_NODE_EVENT = 'node.create';\n\n    /** @var array\u003Cint, NodesPageData> */\n    public array $pages = [];\n\n    public string $nextCursor = '';\n\n    public bool $morePages = true;\n\n    public function mount()\n    {\n        $this->addPage();\n    }\n\n    public function addPage()\n    {\n        if (! $this->morePages) {\n            return;\n        }\n        $nodes = Node::orderBy('path')->cursorPaginate(\n            20, ['*'], 'path',\n            Cursor::fromEncoded($this->nextCursor)\n        );\n        if ($this->morePages = $nodes->hasMorePages()) {\n            $this->nextCursor = $nodes->nextCursor()->encode();\n        }\n\n        collect($nodes->items())\n            ->whenNotEmpty(fn (Collection $items) => (\n                $this->pages[] = NodesPageData::fromNodes($items)\n            ));\n    }\n\n    #[On(self::CREATE_NODE_EVENT)]\n    public function createNode(?int $parentId = null)\n    {\n        $node = Node::create(['parent_id' => $parentId]);\n\n        foreach ($this->pages as $index => $page) {\n            $nextPage = $this->pages[$index + 1] ?? null;\n            if (\n                $node->path >= $page->start_cursor\n                    && $node->path \u003C= $page->end_cursor\n            ) {\n                $this->dispatch(NodesPage::REFRESH_EVENT.$page->key);\n\n                return;\n            } elseif (\n                $node->path \u003C $nextPage?->start_cursor\n                    || (! $nextPage && ! $this->morePages)\n            ) {\n                $this->pages[$index] = new NodesPageData(\n                    $this->pages[$index]->start_cursor,\n                    $node->path\n                );\n\n                return;\n            }\n        }\n        if (! $this->pages) {\n            $this->pages[] = NodesPageData::fromNodes(collect([$node]));\n        }\n    }\n}\n","app/Livewire/Nodes.php",[30,2800,2801,2807,2811,2823,2827,2843,2861,2877,2893,2905,2909,2919,2923,2943,2947,2966,2982,2986,3004,3008,3027,3031,3042,3046,3059,3063,3067,3078,3082,3102,3108,3112,3143,3169,3189,3194,3221,3250,3254,3258,3275,3302,3331,3336,3340,3344,3361,3388,3393,3425,3430,3461,3497,3505,3528,3554,3562,3593,3598,3606,3617,3639,3669,3676,3701,3725,3737,3743,3748,3755,3761,3766,3787,3821,3826,3831],{"__ignoreMap":28},[33,2802,2803,2805],{"class":35,"line":36},[33,2804,319],{"class":148},[33,2806,322],{"class":47},[33,2808,2809],{"class":35,"line":54},[33,2810,204],{"emptyLinePlaceholder":203},[33,2812,2813,2815,2817,2819,2821],{"class":35,"line":69},[33,2814,938],{"class":152},[33,2816,335],{"class":39},[33,2818,338],{"class":178},[33,2820,341],{"class":39},[33,2822,349],{"class":178},[33,2824,2825],{"class":35,"line":79},[33,2826,204],{"emptyLinePlaceholder":203},[33,2828,2829,2831,2833,2835,2837,2839,2841],{"class":35,"line":97},[33,2830,331],{"class":152},[33,2832,335],{"class":334},[33,2834,338],{"class":178},[33,2836,536],{"class":334},[33,2838,338],{"class":178},[33,2840,541],{"class":334},[33,2842,349],{"class":178},[33,2844,2845,2847,2849,2851,2854,2856,2859],{"class":35,"line":110},[33,2846,331],{"class":152},[33,2848,356],{"class":334},[33,2850,338],{"class":178},[33,2852,2853],{"class":334},"Pagination",[33,2855,338],{"class":178},[33,2857,2858],{"class":334},"Cursor",[33,2860,349],{"class":178},[33,2862,2863,2865,2867,2869,2871,2873,2875],{"class":35,"line":122},[33,2864,331],{"class":152},[33,2866,356],{"class":334},[33,2868,338],{"class":178},[33,2870,361],{"class":334},[33,2872,338],{"class":178},[33,2874,1505],{"class":334},[33,2876,349],{"class":178},[33,2878,2879,2881,2883,2885,2887,2889,2891],{"class":35,"line":251},[33,2880,331],{"class":152},[33,2882,1514],{"class":334},[33,2884,338],{"class":178},[33,2886,2107],{"class":334},[33,2888,338],{"class":178},[33,2890,2129],{"class":334},[33,2892,349],{"class":178},[33,2894,2895,2897,2899,2901,2903],{"class":35,"line":272},[33,2896,331],{"class":152},[33,2898,1514],{"class":334},[33,2900,338],{"class":178},[33,2902,2142],{"class":334},[33,2904,349],{"class":178},[33,2906,2907],{"class":35,"line":288},[33,2908,204],{"emptyLinePlaceholder":203},[33,2910,2911,2913,2915,2917],{"class":35,"line":297},[33,2912,407],{"class":72},[33,2914,402],{"class":39},[33,2916,624],{"class":72},[33,2918,2188],{"class":334},[33,2920,2921],{"class":35,"line":302},[33,2922,632],{"class":178},[33,2924,2925,2927,2929,2932,2934,2936,2939,2941],{"class":35,"line":651},[33,2926,654],{"class":72},[33,2928,2199],{"class":72},[33,2930,2931],{"class":47}," CREATE_NODE_EVENT",[33,2933,1004],{"class":148},[33,2935,756],{"class":178},[33,2937,2938],{"class":43},"node.create",[33,2940,227],{"class":178},[33,2942,349],{"class":178},[33,2944,2945],{"class":35,"line":672},[33,2946,204],{"emptyLinePlaceholder":203},[33,2948,2949,2952,2956,2959,2961,2963],{"class":35,"line":678},[33,2950,2951],{"class":637},"    /** ",[33,2953,2955],{"class":2954},"sUF24","@var",[33,2957,2958],{"class":2954}," array",[33,2960,149],{"class":637},[33,2962,2453],{"class":2954},[33,2964,2965],{"class":637},", NodesPageData> */\n",[33,2967,2968,2970,2972,2974,2977,2979],{"class":35,"line":718},[33,2969,654],{"class":72},[33,2971,2958],{"class":152},[33,2973,278],{"class":178},[33,2975,2976],{"class":281},"pages",[33,2978,1004],{"class":148},[33,2980,2981],{"class":178}," [];\n",[33,2983,2984],{"class":35,"line":734},[33,2985,204],{"emptyLinePlaceholder":203},[33,2987,2988,2990,2992,2994,2997,2999,3002],{"class":35,"line":779},[33,2989,654],{"class":72},[33,2991,1549],{"class":152},[33,2993,278],{"class":178},[33,2995,2996],{"class":281},"nextCursor",[33,2998,1004],{"class":148},[33,3000,3001],{"class":178}," ''",[33,3003,349],{"class":178},[33,3005,3006],{"class":35,"line":808},[33,3007,204],{"emptyLinePlaceholder":203},[33,3009,3010,3012,3015,3017,3020,3022,3025],{"class":35,"line":822},[33,3011,654],{"class":72},[33,3013,3014],{"class":152}," bool",[33,3016,278],{"class":178},[33,3018,3019],{"class":281},"morePages",[33,3021,1004],{"class":148},[33,3023,3024],{"class":47}," true",[33,3026,349],{"class":178},[33,3028,3029],{"class":35,"line":828},[33,3030,204],{"emptyLinePlaceholder":203},[33,3032,3033,3035,3037,3040],{"class":35,"line":834},[33,3034,654],{"class":72},[33,3036,657],{"class":72},[33,3038,3039],{"class":39}," mount",[33,3041,1035],{"class":178},[33,3043,3044],{"class":35,"line":839},[33,3045,675],{"class":178},[33,3047,3048,3050,3052,3054,3057],{"class":35,"line":844},[33,3049,1630],{"class":178},[33,3051,1352],{"class":281},[33,3053,413],{"class":148},[33,3055,3056],{"class":39},"addPage",[33,3058,731],{"class":178},[33,3060,3061],{"class":35,"line":850},[33,3062,831],{"class":178},[33,3064,3065],{"class":35,"line":855},[33,3066,204],{"emptyLinePlaceholder":203},[33,3068,3069,3071,3073,3076],{"class":35,"line":871},[33,3070,654],{"class":72},[33,3072,657],{"class":72},[33,3074,3075],{"class":39}," addPage",[33,3077,1035],{"class":178},[33,3079,3080],{"class":35,"line":876},[33,3081,675],{"class":178},[33,3083,3084,3086,3088,3090,3092,3094,3096,3098,3100],{"class":35,"line":896},[33,3085,1866],{"class":152},[33,3087,701],{"class":178},[33,3089,153],{"class":152},[33,3091,278],{"class":178},[33,3093,1352],{"class":281},[33,3095,413],{"class":148},[33,3097,3019],{"class":281},[33,3099,410],{"class":178},[33,3101,715],{"class":178},[33,3103,3104,3106],{"class":35,"line":901},[33,3105,2291],{"class":152},[33,3107,349],{"class":178},[33,3109,3110],{"class":35,"line":1382},[33,3111,1919],{"class":178},[33,3113,3114,3116,3118,3120,3122,3124,3126,3128,3130,3132,3134,3136,3138,3141],{"class":35,"line":1387},[33,3115,1630],{"class":178},[33,3117,448],{"class":281},[33,3119,1004],{"class":148},[33,3121,91],{"class":334},[33,3123,384],{"class":148},[33,3125,2334],{"class":39},[33,3127,224],{"class":178},[33,3129,227],{"class":178},[33,3131,508],{"class":43},[33,3133,227],{"class":178},[33,3135,410],{"class":178},[33,3137,413],{"class":148},[33,3139,3140],{"class":39},"cursorPaginate",[33,3142,1571],{"class":178},[33,3144,3145,3148,3150,3152,3154,3157,3159,3161,3163,3165,3167],{"class":35,"line":1399},[33,3146,3147],{"class":47},"            20",[33,3149,399],{"class":178},[33,3151,1007],{"class":178},[33,3153,227],{"class":178},[33,3155,3156],{"class":43},"*",[33,3158,227],{"class":178},[33,3160,1809],{"class":178},[33,3162,756],{"class":178},[33,3164,508],{"class":43},[33,3166,227],{"class":178},[33,3168,1586],{"class":178},[33,3170,3171,3174,3176,3179,3181,3183,3185,3187],{"class":35,"line":1404},[33,3172,3173],{"class":334},"            Cursor",[33,3175,384],{"class":148},[33,3177,3178],{"class":39},"fromEncoded",[33,3180,1281],{"class":178},[33,3182,1352],{"class":281},[33,3184,413],{"class":148},[33,3186,2996],{"class":281},[33,3188,235],{"class":178},[33,3190,3191],{"class":35,"line":1436},[33,3192,3193],{"class":178},"        );\n",[33,3195,3196,3198,3200,3202,3204,3206,3208,3210,3212,3214,3217,3219],{"class":35,"line":1441},[33,3197,1866],{"class":152},[33,3199,1248],{"class":178},[33,3201,1352],{"class":281},[33,3203,413],{"class":148},[33,3205,3019],{"class":281},[33,3207,1004],{"class":148},[33,3209,278],{"class":178},[33,3211,448],{"class":281},[33,3213,413],{"class":148},[33,3215,3216],{"class":39},"hasMorePages",[33,3218,1878],{"class":178},[33,3220,715],{"class":178},[33,3222,3223,3225,3227,3229,3231,3233,3235,3237,3239,3241,3243,3245,3248],{"class":35,"line":1898},[33,3224,721],{"class":178},[33,3226,1352],{"class":281},[33,3228,413],{"class":148},[33,3230,2996],{"class":281},[33,3232,1004],{"class":148},[33,3234,278],{"class":178},[33,3236,448],{"class":281},[33,3238,413],{"class":148},[33,3240,2996],{"class":39},[33,3242,663],{"class":178},[33,3244,413],{"class":148},[33,3246,3247],{"class":39},"encode",[33,3249,731],{"class":178},[33,3251,3252],{"class":35,"line":1910},[33,3253,1919],{"class":178},[33,3255,3256],{"class":35,"line":1916},[33,3257,204],{"emptyLinePlaceholder":203},[33,3259,3260,3263,3265,3267,3269,3272],{"class":35,"line":1922},[33,3261,3262],{"class":39},"        collect",[33,3264,1281],{"class":178},[33,3266,448],{"class":281},[33,3268,413],{"class":148},[33,3270,3271],{"class":39},"items",[33,3273,3274],{"class":178},"())\n",[33,3276,3277,3279,3282,3284,3287,3289,3291,3293,3295,3297,3299],{"class":35,"line":1927},[33,3278,2331],{"class":148},[33,3280,3281],{"class":39},"whenNotEmpty",[33,3283,224],{"class":178},[33,3285,3286],{"class":72},"fn",[33,3288,701],{"class":178},[33,3290,1609],{"class":334},[33,3292,707],{"class":178},[33,3294,3271],{"class":281},[33,3296,410],{"class":178},[33,3298,1714],{"class":178},[33,3300,3301],{"class":178}," (\n",[33,3303,3304,3307,3309,3311,3313,3316,3318,3320,3322,3325,3327,3329],{"class":35,"line":1954},[33,3305,3306],{"class":178},"                $",[33,3308,1352],{"class":281},[33,3310,413],{"class":148},[33,3312,2976],{"class":281},[33,3314,3315],{"class":178},"[]",[33,3317,1004],{"class":148},[33,3319,1532],{"class":334},[33,3321,384],{"class":148},[33,3323,3324],{"class":39},"fromNodes",[33,3326,1281],{"class":178},[33,3328,3271],{"class":281},[33,3330,235],{"class":178},[33,3332,3333],{"class":35,"line":1980},[33,3334,3335],{"class":178},"            ));\n",[33,3337,3338],{"class":35,"line":1985},[33,3339,831],{"class":178},[33,3341,3342],{"class":35,"line":2012},[33,3343,204],{"emptyLinePlaceholder":203},[33,3345,3346,3349,3351,3353,3355,3357,3359],{"class":35,"line":2017},[33,3347,3348],{"class":334},"    #[On",[33,3350,224],{"class":178},[33,3352,1074],{"class":72},[33,3354,384],{"class":148},[33,3356,2484],{"class":47},[33,3358,410],{"class":178},[33,3360,2176],{"class":334},[33,3362,3364,3366,3368,3371,3373,3376,3378,3380,3382,3384,3386],{"class":35,"line":3363},47,[33,3365,654],{"class":72},[33,3367,657],{"class":72},[33,3369,3370],{"class":39}," createNode",[33,3372,224],{"class":178},[33,3374,3375],{"class":148},"?",[33,3377,2453],{"class":152},[33,3379,278],{"class":178},[33,3381,2458],{"class":281},[33,3383,1004],{"class":148},[33,3385,2282],{"class":47},[33,3387,235],{"class":178},[33,3389,3391],{"class":35,"line":3390},48,[33,3392,675],{"class":178},[33,3394,3396,3398,3400,3402,3404,3406,3408,3411,3413,3415,3417,3419,3421,3423],{"class":35,"line":3395},49,[33,3397,1630],{"class":178},[33,3399,1079],{"class":281},[33,3401,1004],{"class":148},[33,3403,91],{"class":334},[33,3405,384],{"class":148},[33,3407,686],{"class":39},[33,3409,3410],{"class":178},"([",[33,3412,227],{"class":178},[33,3414,452],{"class":43},[33,3416,227],{"class":178},[33,3418,1714],{"class":148},[33,3420,278],{"class":178},[33,3422,2458],{"class":281},[33,3424,1824],{"class":178},[33,3426,3428],{"class":35,"line":3427},50,[33,3429,204],{"emptyLinePlaceholder":203},[33,3431,3433,3436,3438,3440,3442,3444,3446,3448,3450,3452,3454,3457,3459],{"class":35,"line":3432},51,[33,3434,3435],{"class":152},"        foreach",[33,3437,1248],{"class":178},[33,3439,1352],{"class":281},[33,3441,413],{"class":148},[33,3443,2976],{"class":281},[33,3445,2564],{"class":152},[33,3447,278],{"class":178},[33,3449,803],{"class":281},[33,3451,1714],{"class":148},[33,3453,278],{"class":178},[33,3455,3456],{"class":281},"page",[33,3458,410],{"class":178},[33,3460,715],{"class":178},[33,3462,3464,3466,3469,3471,3473,3475,3477,3479,3482,3484,3486,3488,3491,3493,3495],{"class":35,"line":3463},52,[33,3465,721],{"class":178},[33,3467,3468],{"class":281},"nextPage",[33,3470,1004],{"class":148},[33,3472,278],{"class":178},[33,3474,1352],{"class":281},[33,3476,413],{"class":148},[33,3478,2976],{"class":281},[33,3480,3481],{"class":178},"[$",[33,3483,803],{"class":281},[33,3485,1228],{"class":148},[33,3487,1231],{"class":47},[33,3489,3490],{"class":178},"]",[33,3492,1262],{"class":148},[33,3494,2282],{"class":47},[33,3496,349],{"class":178},[33,3498,3500,3503],{"class":35,"line":3499},53,[33,3501,3502],{"class":152},"            if",[33,3504,3301],{"class":178},[33,3506,3508,3510,3512,3514,3516,3519,3521,3523,3525],{"class":35,"line":3507},54,[33,3509,3306],{"class":178},[33,3511,1079],{"class":281},[33,3513,413],{"class":148},[33,3515,508],{"class":281},[33,3517,3518],{"class":148}," >=",[33,3520,278],{"class":178},[33,3522,3456],{"class":281},[33,3524,413],{"class":148},[33,3526,3527],{"class":281},"start_cursor\n",[33,3529,3531,3534,3536,3538,3540,3542,3545,3547,3549,3551],{"class":35,"line":3530},55,[33,3532,3533],{"class":152},"                    &&",[33,3535,278],{"class":178},[33,3537,1079],{"class":281},[33,3539,413],{"class":148},[33,3541,508],{"class":281},[33,3543,3544],{"class":148}," \u003C=",[33,3546,278],{"class":178},[33,3548,3456],{"class":281},[33,3550,413],{"class":148},[33,3552,3553],{"class":281},"end_cursor\n",[33,3555,3557,3560],{"class":35,"line":3556},56,[33,3558,3559],{"class":178},"            )",[33,3561,715],{"class":178},[33,3563,3565,3567,3569,3571,3573,3575,3577,3579,3581,3583,3585,3587,3589,3591],{"class":35,"line":3564},57,[33,3566,3306],{"class":178},[33,3568,1352],{"class":281},[33,3570,413],{"class":148},[33,3572,2475],{"class":39},[33,3574,224],{"class":178},[33,3576,2025],{"class":334},[33,3578,384],{"class":148},[33,3580,2162],{"class":47},[33,3582,1307],{"class":148},[33,3584,707],{"class":178},[33,3586,3456],{"class":281},[33,3588,413],{"class":148},[33,3590,1457],{"class":281},[33,3592,428],{"class":178},[33,3594,3596],{"class":35,"line":3595},58,[33,3597,204],{"emptyLinePlaceholder":203},[33,3599,3601,3604],{"class":35,"line":3600},59,[33,3602,3603],{"class":152},"                return",[33,3605,349],{"class":178},[33,3607,3609,3612,3615],{"class":35,"line":3608},60,[33,3610,3611],{"class":178},"            }",[33,3613,3614],{"class":152}," elseif",[33,3616,3301],{"class":178},[33,3618,3620,3622,3624,3626,3628,3631,3633,3635,3637],{"class":35,"line":3619},61,[33,3621,3306],{"class":178},[33,3623,1079],{"class":281},[33,3625,413],{"class":148},[33,3627,508],{"class":281},[33,3629,3630],{"class":148}," \u003C",[33,3632,278],{"class":178},[33,3634,3468],{"class":281},[33,3636,1257],{"class":148},[33,3638,3527],{"class":281},[33,3640,3642,3645,3647,3649,3651,3653,3656,3659,3661,3663,3665,3667],{"class":35,"line":3641},62,[33,3643,3644],{"class":152},"                    ||",[33,3646,701],{"class":178},[33,3648,153],{"class":152},[33,3650,278],{"class":178},[33,3652,3468],{"class":281},[33,3654,3655],{"class":152}," &&",[33,3657,3658],{"class":152}," !",[33,3660,278],{"class":178},[33,3662,1352],{"class":281},[33,3664,413],{"class":148},[33,3666,3019],{"class":281},[33,3668,235],{"class":178},[33,3670,3672,3674],{"class":35,"line":3671},63,[33,3673,3559],{"class":178},[33,3675,715],{"class":178},[33,3677,3679,3681,3683,3685,3687,3689,3691,3693,3695,3697,3699],{"class":35,"line":3678},64,[33,3680,3306],{"class":178},[33,3682,1352],{"class":281},[33,3684,413],{"class":148},[33,3686,2976],{"class":281},[33,3688,3481],{"class":178},[33,3690,803],{"class":281},[33,3692,3490],{"class":178},[33,3694,1004],{"class":148},[33,3696,60],{"class":152},[33,3698,1532],{"class":334},[33,3700,1571],{"class":178},[33,3702,3704,3707,3709,3711,3713,3715,3717,3719,3721,3723],{"class":35,"line":3703},65,[33,3705,3706],{"class":178},"                    $",[33,3708,1352],{"class":281},[33,3710,413],{"class":148},[33,3712,2976],{"class":281},[33,3714,3481],{"class":178},[33,3716,803],{"class":281},[33,3718,3490],{"class":178},[33,3720,413],{"class":148},[33,3722,1583],{"class":281},[33,3724,1586],{"class":178},[33,3726,3728,3730,3732,3734],{"class":35,"line":3727},66,[33,3729,3706],{"class":178},[33,3731,1079],{"class":281},[33,3733,413],{"class":148},[33,3735,3736],{"class":281},"path\n",[33,3738,3740],{"class":35,"line":3739},67,[33,3741,3742],{"class":178},"                );\n",[33,3744,3746],{"class":35,"line":3745},68,[33,3747,204],{"emptyLinePlaceholder":203},[33,3749,3751,3753],{"class":35,"line":3750},69,[33,3752,3603],{"class":152},[33,3754,349],{"class":178},[33,3756,3758],{"class":35,"line":3757},70,[33,3759,3760],{"class":178},"            }\n",[33,3762,3764],{"class":35,"line":3763},71,[33,3765,1919],{"class":178},[33,3767,3769,3771,3773,3775,3777,3779,3781,3783,3785],{"class":35,"line":3768},72,[33,3770,1866],{"class":152},[33,3772,701],{"class":178},[33,3774,153],{"class":152},[33,3776,278],{"class":178},[33,3778,1352],{"class":281},[33,3780,413],{"class":148},[33,3782,2976],{"class":281},[33,3784,410],{"class":178},[33,3786,715],{"class":178},[33,3788,3790,3792,3794,3796,3798,3800,3802,3804,3806,3808,3810,3813,3816,3818],{"class":35,"line":3789},73,[33,3791,721],{"class":178},[33,3793,1352],{"class":281},[33,3795,413],{"class":148},[33,3797,2976],{"class":281},[33,3799,3315],{"class":178},[33,3801,1004],{"class":148},[33,3803,1532],{"class":334},[33,3805,384],{"class":148},[33,3807,3324],{"class":39},[33,3809,224],{"class":178},[33,3811,3812],{"class":39},"collect",[33,3814,3815],{"class":178},"([$",[33,3817,1079],{"class":281},[33,3819,3820],{"class":178},"]));\n",[33,3822,3824],{"class":35,"line":3823},74,[33,3825,1919],{"class":178},[33,3827,3829],{"class":35,"line":3828},75,[33,3830,831],{"class":178},[33,3832,3834],{"class":35,"line":3833},76,[33,3835,1444],{"class":178},[23,3837,3840],{"className":139,"code":3838,"filename":3839,"language":82,"meta":28,"style":28},"\u003Cdiv>\n    \u003Cbutton class=\"border\" wire:click=\"createNode\">Add Node\u003C/button>\n    @foreach ($this->pages as $index => $page)\n        \u003Clivewire:nodes-page :wire:key=\"$page->key\" :pageIndex=\"$index\" :pageData=\"$page\" />\n    @endforeach\n    @if ($this->morePages)\n        \u003Cbutton class=\"border\" wire:click=\"addPage\">Load More\u003C/button>\n    @endif\n\u003C/div>\n","resources/views/livewire/nodes.blade.php",[30,3841,3842,3850,3895,3923,3989,3995,4012,4056,4063],{"__ignoreMap":28},[33,3843,3844,3846,3848],{"class":35,"line":36},[33,3845,149],{"class":148},[33,3847,2544],{"class":47},[33,3849,162],{"class":148},[33,3851,3852,3855,3857,3859,3861,3863,3865,3867,3869,3871,3873,3875,3877,3880,3882,3884,3887,3889,3891,3893],{"class":35,"line":54},[33,3853,3854],{"class":148},"    \u003C",[33,3856,2700],{"class":47},[33,3858,187],{"class":72},[33,3860,175],{"class":148},[33,3862,179],{"class":178},[33,3864,2709],{"class":43},[33,3866,179],{"class":178},[33,3868,2714],{"class":47},[33,3870,666],{"class":178},[33,3872,2719],{"class":47},[33,3874,175],{"class":148},[33,3876,179],{"class":178},[33,3878,3879],{"class":43},"createNode",[33,3881,179],{"class":178},[33,3883,2671],{"class":148},[33,3885,3886],{"class":47},"Add",[33,3888,91],{"class":47},[33,3890,240],{"class":148},[33,3892,2700],{"class":47},[33,3894,162],{"class":148},[33,3896,3897,3899,3901,3903,3905,3907,3909,3911,3913,3915,3917,3919,3921],{"class":35,"line":69},[33,3898,218],{"class":148},[33,3900,2553],{"class":152},[33,3902,1248],{"class":178},[33,3904,1352],{"class":281},[33,3906,413],{"class":148},[33,3908,2976],{"class":281},[33,3910,2564],{"class":152},[33,3912,278],{"class":178},[33,3914,803],{"class":281},[33,3916,1714],{"class":148},[33,3918,278],{"class":178},[33,3920,3456],{"class":281},[33,3922,235],{"class":178},[33,3924,3925,3927,3930,3932,3934,3936,3938,3941,3944,3946,3948,3950,3953,3955,3957,3959,3961,3963,3966,3968,3970,3972,3974,3976,3978,3980,3982,3984,3986],{"class":35,"line":79},[33,3926,2626],{"class":148},[33,3928,3929],{"class":47},"livewire",[33,3931,666],{"class":178},[33,3933,448],{"class":47},[33,3935,1653],{"class":148},[33,3937,3456],{"class":47},[33,3939,3940],{"class":178}," :",[33,3942,3943],{"class":47},"wire",[33,3945,666],{"class":178},[33,3947,1457],{"class":47},[33,3949,175],{"class":148},[33,3951,3952],{"class":178},"\"$",[33,3954,3456],{"class":281},[33,3956,413],{"class":148},[33,3958,1457],{"class":281},[33,3960,179],{"class":178},[33,3962,3940],{"class":178},[33,3964,3965],{"class":47},"pageIndex",[33,3967,175],{"class":148},[33,3969,3952],{"class":178},[33,3971,803],{"class":281},[33,3973,179],{"class":178},[33,3975,3940],{"class":178},[33,3977,2229],{"class":47},[33,3979,175],{"class":148},[33,3981,3952],{"class":178},[33,3983,3456],{"class":281},[33,3985,179],{"class":178},[33,3987,3988],{"class":148}," />\n",[33,3990,3991,3993],{"class":35,"line":97},[33,3992,218],{"class":148},[33,3994,2774],{"class":152},[33,3996,3997,3999,4002,4004,4006,4008,4010],{"class":35,"line":110},[33,3998,218],{"class":148},[33,4000,4001],{"class":152},"if",[33,4003,1248],{"class":178},[33,4005,1352],{"class":281},[33,4007,413],{"class":148},[33,4009,3019],{"class":281},[33,4011,235],{"class":178},[33,4013,4014,4016,4018,4020,4022,4024,4026,4028,4030,4032,4034,4036,4038,4040,4042,4044,4047,4050,4052,4054],{"class":35,"line":122},[33,4015,2626],{"class":148},[33,4017,2700],{"class":47},[33,4019,187],{"class":72},[33,4021,175],{"class":148},[33,4023,179],{"class":178},[33,4025,2709],{"class":43},[33,4027,179],{"class":178},[33,4029,2714],{"class":47},[33,4031,666],{"class":178},[33,4033,2719],{"class":47},[33,4035,175],{"class":148},[33,4037,179],{"class":178},[33,4039,3056],{"class":43},[33,4041,179],{"class":178},[33,4043,2671],{"class":148},[33,4045,4046],{"class":47},"Load",[33,4048,4049],{"class":47}," More",[33,4051,240],{"class":148},[33,4053,2700],{"class":47},[33,4055,162],{"class":148},[33,4057,4058,4060],{"class":35,"line":251},[33,4059,218],{"class":148},[33,4061,4062],{"class":152},"endif\n",[33,4064,4065,4067,4069],{"class":35,"line":272},[33,4066,240],{"class":148},[33,4068,2544],{"class":47},[33,4070,162],{"class":148},[11,4072,4074],{"id":4073},"thats-it","That's It! ",[16,4076,4077,4078,4080],{},"While this implementation serves as a starting point, there are opportunities\nfor further refinement. For instance, we could implement safeguards to prevent\n",[30,4079,508],{}," parts from exceeding the padding limit, ensuring accurate sorting. We\ncould also split pages into two if too many nodes are added without a page\nrefresh. This is intended as a demonstration, and therefore we will leave it at\nthat.",[16,4082,4083],{},"I hope this guide has provided you with a clear and practical approach to\nimplementing MySQL tree structures with infinite scrolling in Livewire. I\nlearned quite a lot working on this project, and I hope you did too!",[4085,4086,4087],"style",{},"html pre.shiki code .s59W0, html code.shiki .s59W0{--shiki-default:#FABD2F}html pre.shiki code .sTqo2, html code.shiki .sTqo2{--shiki-default:#B8BB26}html pre.shiki code .ssIPD, html code.shiki .ssIPD{--shiki-default:#D3869B}html pre.shiki code .sG605, html code.shiki .sG605{--shiki-default:#FE8019}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sM2RB, html code.shiki .sM2RB{--shiki-default:#8EC07C}html pre.shiki code .sBQf5, html code.shiki .sBQf5{--shiki-default:#FB4934}html pre.shiki code .svnLg, html code.shiki .svnLg{--shiki-default:#A89984}html pre.shiki code .sMWUE, html code.shiki .sMWUE{--shiki-default:#83A598}html pre.shiki code .sM0OT, html code.shiki .sM0OT{--shiki-default:#EBDBB2}html pre.shiki code .s-UKz, html code.shiki .s-UKz{--shiki-default:#928374;--shiki-default-font-style:italic}html pre.shiki code .sUF24, html code.shiki .sUF24{--shiki-default:#FB4934;--shiki-default-font-style:italic}",{"title":28,"searchDepth":54,"depth":54,"links":4089},[4090,4091,4092,4093,4094],{"id":13,"depth":54,"text":14},{"id":441,"depth":54,"text":442},{"id":485,"depth":54,"text":486},{"id":495,"depth":54,"text":496},{"id":4073,"depth":54,"text":4074},"md","/images/infinite-scroll-with-mysql-tree-structures-in-livewire.png",{},"/article/infinite-scroll-with-mysql-tree-structures-in-livewire","2025-09-10",{"title":6,"description":28},"article/infinite-scroll-with-mysql-tree-structures-in-livewire","PB-NPxbknZUh--XyOp46J0QhnHdxfgaJF7_dYqm89mE",1776970087495]