Skip to content

[Proposal]: Allow path pattern names with partitioning #2238

@stloyd

Description

@stloyd

Describe the Proposal

Right now, code like this:

df()
    ->extract(/* */)
    ->partitionBy('order-year', 'order-month', 'order-name')
    ->load(
        to_csv(__DIR__.'/output/{order-name}.csv')
    );

Would fail because Path doesn't allow patterns.

API Adjustments

# UnixPath.php

    public function addPartitions(Partition $partition, Partition ...$partitions) : self
    {
        /** @var Partition[] $partitions */
        $partitions = [$partition, ...$partitions];

        // Here are first changes
        if ($this->isPathPattern($this->path) && [] === $partitions) {
            throw new InvalidArgumentException("Can't use partitions with non-pattern path.");
        }

        $pathInfo = \pathinfo($this->path);
        $dirname = $pathInfo['dirname'] ?? '';
        $filename = $pathInfo['filename'] ?? '';
        $extension = $pathInfo['extension'] ?? '';

        // Here lies most of the "magic"
        if (str_starts_with($filename, '{') && str_ends_with($filename, '}')) {
            foreach ($partitions as $index => $partition) {
                if (!str_contains($filename, $partition->name)) {
                    continue;
                }

                $filename = $partition->value;
                unset($partitions[$index]);
            }
        }

        $basename = $filename . '.' . $extension;
        if ($this->isPathPattern($basename)) {
            throw new InvalidArgumentException("Can't resolve path pattern.");
        }

        $partitionsString = \implode('/', \array_map(static fn (Partition $p) => $p->name . '=' . $p->value, $partitions));

        return match ($dirname) {
            '', '.' => new self($this->protocol->scheme() . '/' . $partitionsString . '/' . $basename, $this->options),
            '/', '\\' => new self($this->protocol->scheme() . '/' . $partitionsString . '/' . $basename, $this->options),
            default => new self($this->protocol->scheme() . $dirname . '/' . $partitionsString . '/' . $basename, $this->options),
        };
    }

Are you intending to also work on proposed change?

Yes

Are you interested in sponsoring this change?

None

Integration & Dependencies

No response

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions