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