Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add way to create IDs that are meant for querying a specific timestamp #9

Merged
merged 5 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Contracts/MakesBits.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public function make(): Bits;

public function makeFromTimestamp(CarbonInterface $timestamp): Bits;

public function firstForTimestamp(CarbonInterface $timestamp): Bits;

public function fromId(int|string $id): Bits;

public function coerce(int|string|Bits $value): Bits;
Expand Down
13 changes: 13 additions & 0 deletions src/Factories/GenericFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ public function makeFromTimestamp(CarbonInterface $timestamp): Bits
return new Bits($values, $this->config, $this->epoch);
}

public function firstForTimestamp(CarbonInterface $timestamp): Bits
{
$timestamp = $this->diffFromEpoch($timestamp);

$values = $this->config->organize(
ids: new WorkerIds(...array_map(fn() => 0, $this->ids->ids)),
timestamp: $timestamp,
sequence: 0
);

return new Bits($values, $this->config, $this->epoch);
}

public function fromId(int|string $id): Bits
{
$values = $this->config->parse((int) $id);
Expand Down
7 changes: 7 additions & 0 deletions src/Factories/SnowflakeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ public function makeFromTimestamp(CarbonInterface $timestamp): Snowflake
return new Snowflake($timestamp, $this->datacenter_id, $this->worker_id, $sequence, $this->epoch, $this->config);
}

public function firstForTimestamp(CarbonInterface $timestamp): Snowflake
{
$timestamp = $this->diffFromEpoch($timestamp);

return new Snowflake($timestamp, 0, 0, 0, $this->epoch, $this->config);
}

public function fromId(int|string $id): Snowflake
{
[$_, $timestamp, $datacenter_id, $worker_id, $sequence] = $this->config->parse((int) $id);
Expand Down
7 changes: 7 additions & 0 deletions src/Factories/SonyflakeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ public function makeFromTimestamp(CarbonInterface $timestamp): Sonyflake
return new Sonyflake($timestamp, $sequence, $this->machine_id, $this->epoch, $this->config);
}

public function firstForTimestamp(CarbonInterface $timestamp): Sonyflake
{
$timestamp = $this->diffFromEpoch($timestamp);

return new Sonyflake($timestamp, 0, 0, $this->epoch, $this->config);
}

public function fromId(int|string $id): Sonyflake
{
[$timestamp, $sequence, $machine_id] = $this->config->parse((int) $id);
Expand Down
20 changes: 18 additions & 2 deletions tests/Unit/CustomTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,28 @@ public function test_a_bit_can_be_created_for_a_specific_timestamp(): void
$factory = $this->getBitsFactory(14);

$bits = $factory->makeFromTimestamp(now()->addMicrosecond());
$this->assertEquals([1, 14, 0], $bits->values->all());

$this->assertEquals(1, $bits->values[0]);
$bits = $factory->makeFromTimestamp(now()->addMicrosecond());
$this->assertEquals([1, 14, 1], $bits->values->all());

$bits = $factory->makeFromTimestamp(now()->addMicroseconds(42));
$this->assertEquals([42, 14, 0], $bits->values->all());
}

public function test_a_bit_can_be_created_for_querying_by_a_specific_timestamp(): void
{
Date::setTestNow(now());

$factory = $this->getBitsFactory(14);

$bits = $factory->firstForTimestamp(now()->addMicrosecond());

$this->assertEquals([1, 0, 0], $bits->values->all());

$bits = $factory->firstForTimestamp(now()->addMicroseconds(42));

$this->assertEquals(42, $bits->values[0]);
$this->assertEquals([42, 0, 0], $bits->values->all());
}

protected function getBitsFactory(int $id, ResolvesSequences $sequence = null): GenericFactory
Expand Down
40 changes: 39 additions & 1 deletion tests/Unit/SnowflakeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,53 @@ public function test_it_sleeps_1ms_when_sequence_limit_is_reached(): void

public function test_a_snowflake_can_be_created_for_a_specific_timestamp(): void
{
$factory = $this->app->make(MakesSnowflakes::class);
$factory = new SnowflakeFactory(
epoch: now(),
datacenter_id: 1,
worker_id: 15,
config: app(SnowflakesConfig::class),
sequence: new InMemorySequenceResolver(),
);

$snowflake = $factory->makeFromTimestamp($factory->epoch->toImmutable()->addMillisecond());

$this->assertEquals(1, $snowflake->timestamp);
$this->assertEquals(1, $snowflake->datacenter_id);
$this->assertEquals(15, $snowflake->worker_id);
$this->assertEquals(0, $snowflake->sequence);

$snowflake = $factory->makeFromTimestamp($factory->epoch->toImmutable()->addMillisecond());

$this->assertEquals(1, $snowflake->timestamp);
$this->assertEquals(1, $snowflake->datacenter_id);
$this->assertEquals(15, $snowflake->worker_id);
$this->assertEquals(1, $snowflake->sequence);

$snowflake = $factory->makeFromTimestamp($factory->epoch->toImmutable()->addMilliseconds(42));

$this->assertEquals(42, $snowflake->timestamp);
$this->assertEquals(1, $snowflake->datacenter_id);
$this->assertEquals(15, $snowflake->worker_id);
$this->assertEquals(0, $snowflake->sequence);
}

public function test_a_snowflake_can_be_created_for_querying_by_a_specific_timestamp(): void
{
$factory = $this->app->make(MakesSnowflakes::class);

$snowflake = $factory->firstForTimestamp($factory->epoch->toImmutable()->addMillisecond());

$this->assertEquals(1, $snowflake->timestamp);
$this->assertEquals(0, $snowflake->datacenter_id);
$this->assertEquals(0, $snowflake->worker_id);
$this->assertEquals(0, $snowflake->sequence);

$snowflake = $factory->firstForTimestamp($factory->epoch->toImmutable()->addMilliseconds(42));

$this->assertEquals(42, $snowflake->timestamp);
$this->assertEquals(0, $snowflake->datacenter_id);
$this->assertEquals(0, $snowflake->worker_id);
$this->assertEquals(0, $snowflake->sequence);
}

public function test_a_snowflake_can_be_serialized_to_json(): void
Expand Down
19 changes: 18 additions & 1 deletion tests/Unit/SonyflakeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public function test_it_sleeps_10ms_when_sequence_limit_is_reached(): void
Sleep::assertSlept(fn(CarbonInterval $interval) => (int) $interval->totalMicroseconds === 10000);
}

public function test_a_snowflake_can_be_created_for_a_specific_timestamp(): void
public function test_a_sonyflake_can_be_created_for_a_specific_timestamp(): void
{
$factory = $this->app->make(MakesSonyflakes::class);

Expand All @@ -164,4 +164,21 @@ public function test_a_snowflake_can_be_created_for_a_specific_timestamp(): void

$this->assertEquals(42, $sonyflake->timestamp);
}

public function test_a_sonyflake_can_be_created_for_querying_by_a_specific_timestamp(): void
{
$factory = $this->app->make(MakesSonyflakes::class);

$sonyflake = $factory->firstForTimestamp($factory->epoch->toImmutable()->addMilliseconds(10));

$this->assertEquals(1, $sonyflake->timestamp);
$this->assertEquals(0, $sonyflake->sequence);
$this->assertEquals(0, $sonyflake->machine_id);

$sonyflake = $factory->firstForTimestamp($factory->epoch->toImmutable()->addMilliseconds(420));

$this->assertEquals(42, $sonyflake->timestamp);
$this->assertEquals(0, $sonyflake->sequence);
$this->assertEquals(0, $sonyflake->machine_id);
}
}
Loading