Mon Jul 15 2019
Json field queries
SELECT
*, `payload`->"$[0].eCommerceOrderId" AS `e_commerce_order_id`
FROM
pendingOrderStatus
WHERE
`status` = 'sent';
SELECT
id, `order`->>'$.e_commerce_order_id' AS `e_commerce_order_id`
FROM
order_log_transforms
WHERE
`order`->>'$.e_commerce_order_id' IS NOT NULL;
Wed Jul 17 2019
Importing from the source table in one database to the destination in another database.
INSERT INTO `materials-staging`.`files` (`id`, `path`, `type`, `hash`, `material_id`, `active`, `created_at`, `updated_at`, `deleted_at`)
SELECT
*
FROM
`materials_staging`.`mat_files`;
Mon Jul 8
storage/app/public/images/HELL/originalFileName.extension
. The image column saves only the name as it already appears.$this->model()->path
. At a resource level we can get the model columns used because it's defined as $this->model. Because we're on the detail view the path in this case is filled in. We don't need methods that include the models.This is one of the biggest "aha!" moments with Nova where the docs aren't very intuitive nor do they promote this in any meaningful way in the examples I've seen.
Image::make('Header Image', 'image')
->disk('public')
->store(function (Request $request, \App\Models\Bucket $model) {
$path = "images/{$model->path}";
$file = $request->image->storeAs($path, $request->image->getClientOriginalName(), 'public');
return [
'image' => $request->image->getClientOriginalName(),
];
})
->prunable()
->preview(function ($image, $disk) {
return $image ? \Storage::disk($disk)->url("images/{$this->model()->path}/$image") : null;
})
->thumbnail(function ($image, $disk) {
return $image ? \Storage::disk($disk)->url("images/{$this->model()->path}/$image") : null;
}),
Tue Jul 9
getPathAttribute()
essentially creates our path value in the same way from our slug and it's only used during the create model upload.This is sleight of hand at its finest, the real path column is what we're looking for but we're hacking in functionality to work at the create form level, bypassing the need to restrict this to only during edits.
public function getPathAttribute()
{
$path = (array_has($this->attributes, 'path') && $this->attributes['path']) ? $this->attributes['path'] : null;
// We only care to calculate the path in the same manner as our creating method when the model is first used
if ($path === null) {
$slug = (array_has($this->attributes, 'slug') && $this->attributes['slug']) ? static::stripSpecialCharacters($this->attributes['slug']) : null;
return $slug;
}
return $path;
}
protected static function boot()
{
parent::boot();
static::created(function(Bucket $bucket) {
$bucket->path = static::stripSpecialCharacters($bucket->slug);
$bucket->save();
});
}
Wed Jul 10
Filter the specific keys to look for:
> keys horizon:queue*
1) "horizon:queues:orders:transfer:reserved"
2) "horizon:queue:orders:transform"
3) "horizon:queue:orders:transfer"
4) "horizon:queues:orders:transfer"
Get the type of our keys:
> type "horizon:queues:orders:transfer:reserved"
zset
> type "horizon:queue:orders:transform"
hash
> type "horizon:queue:orders:transfer"
hash
> type "horizon:queues:orders:transfer"
list
> type "horizon:job:App\\Jobs\\PendingOrderTransformJob"
hash
> type "horizon:job:App\\Jobs\\PendingOrderTransferJob"
hash
Look at the values for the specific keys:
> zrange "horizon:queues:orders:transfer:reserved" 0 2 WITHSCORES
1) "{\"type\":\"job\",\"timeout\":null,\"tags\":[\"App\\\\Model\\\\PendingOrderStatus:1258\"],\"id\":\"2520\",\"data\":{\"command\":\"O:32:\\\"App\\\\Jobs\\\\PendingOrderTransferJob\\\":8:{s:9:\\\"\\u0000*\\u0000status\\\";O:45:\\\"Illuminate\\\\Contracts\\\\Database\\\\ModelIdentifier\\\":3:{s:5:\\\"class\\\";s:28:\\\"App\\\\Model\\\\PendingOrderStatus\\\";s:2:\\\"id\\\";i:1258;s:10:\\\"connection\\\";s:5:\\\"mysql\\\";}s:6:\\\"\\u0000*\\u0000job\\\";N;s:10:\\\"connection\\\";s:13:\\\"redis:horizon\\\";s:5:\\\"queue\\\";s:15:\\\"orders:transfer\\\";s:15:\\\"chainConnection\\\";N;s:10:\\\"chainQueue\\\";N;s:5:\\\"delay\\\";N;s:7:\\\"chained\\\";a:0:{}}\",\"commandName\":\"App\\\\Jobs\\\\PendingOrderTransferJob\"},\"displayName\":\"App\\\\Jobs\\\\PendingOrderTransferJob\",\"timeoutAt\":1562789478,\"pushedAt\":\"1562787678.5943\",\"maxTries\":null,\"job\":\"Illuminate\\\\Queue\\\\CallQueuedHandler@call\",\"attempts\":3}"
2) "1562788306"
> hgetall "horizon:queue:orders:transfer"
1) "throughput"
2) "52"
3) "runtime"
4) "5623.0248076923099"
> lrange "horizon:queues:orders:transfer" 0 99
...
47) "{\"type\":\"job\",\"timeout\":null,\"tags\":[\"App\\\\Model\\\\PendingOrderStatus:1280\"],\"id\":\"2564\",\"data\":{\"command\":\"O:32:\\\"App\\\\Jobs\\\\PendingOrderTransferJob\\\":8:{s:9:\\\"\\u0000*\\u0000status\\\";O:45:\\\"Illuminate\\\\Contracts\\\\Database\\\\ModelIdentifier\\\":3:{s:5:\\\"class\\\";s:28:\\\"App\\\\Model\\\\PendingOrderStatus\\\";s:2:\\\"id\\\";i:1280;s:10:\\\"connection\\\";s:5:\\\"mysql\\\";}s:6:\\\"\\u0000*\\u0000job\\\";N;s:10:\\\"connection\\\";s:13:\\\"redis:horizon\\\";s:5:\\\"queue\\\";s:15:\\\"orders:transfer\\\";s:15:\\\"chainConnection\\\";N;s:10:\\\"chainQueue\\\";N;s:5:\\\"delay\\\";N;s:7:\\\"chained\\\";a:0:{}}\",\"commandName\":\"App\\\\Jobs\\\\PendingOrderTransferJob\"},\"displayName\":\"App\\\\Jobs\\\\PendingOrderTransferJob\",\"timeoutAt\":1562789480,\"pushedAt\":\"1562787680.4057\",\"maxTries\":null,\"job\":\"Illuminate\\\\Queue\\\\CallQueuedHandler@call\",\"attempts\":3}"
> hgetall "horizon:job:App\\Jobs\\PendingOrderTransferJob"
1) "throughput"
2) "7"
3) "runtime"
4) "7738.0300000000007"
Dump our entire key list (the -n
option specifies the database):
> redis-cli -n 3 keys "*" > horizon.keys
horizon:snapshot:job:App\\Jobs\\PendingOrderTransformJob
horizon:supervisor:orange-business-rules-swap-f6S1:supervisor-order-transform
horizon:job:App\\Jobs\\PendingOrderTransformJob
horizon:failed_jobs
horizon:snapshot:job:App\\Jobs\\PendingOrderTransferJob
horizon:masters
horizon:job_id
horizon:queues:orders:transfer:reserved
horizon:snapshot:queue:orders:transform
horizon:supervisor:orange-business-rules-swap-f6S1:supervisor-default
horizon:supervisor:orange-business-rules-swap-f6S1:supervisor-order-transfer
horizon:supervisors
horizon:recent_failed_jobs
horizon:master:orange-business-rules-swap-f6S1
horizon:job:App\\Jobs\\PendingOrderTransferJob
horizon:measured_jobs
horizon:queue:orders:transform
horizon:measured_queues
horizon:recent_jobs
horizon:queue:orders:transfer
horizon:last_snapshot_at
horizon:monitor:time-to-clear
horizon:snapshot:queue:orders:transfer
horizon:metrics:snapshot
horizon:queues:orders:transfer
horizon:id
or horizon:failed*
.Thu Jul 11
Do not use Redis::throtle()
with the retryUntil()
method.
Redis::throttle($key)->allow(1)->every(60)->then(function () {
$this->execute();
}, function () {
// Could not obtain lock...
return $this->release(10);
});
/**
* Determine the time at which the job should timeout.
*
* @return \DateTime
*/
public function retryUntil()
{
return now()->addMinutes(60);
}
Fri Jul 12
Setting a redis override for our custom systemd configuration
sudo systemctl edit redis-server
The command opens nano to an override file in /etc/systemd/system where we paste the following:
[Service]
ReadWriteDirectories=-/mnt/orange-business-rules/var/lib/redis
Thu Jul 11
Maps
Map.fetch(@person, :age)
returns {:ok, value}MapSets
MapSet.size(new_set)
returns an integer for the size (think array length in JavaScript)MapSet.member?(@set, 3)
returns a booleanMapSet.new(@set, fn x -> 3 * x end)
creates a new set using the function results of 3 * (each value in the set).MapSet.to_list(@set)
looks for brackets not braces. I confused a list with a tuple.Tue Jul 2
This wasn't quite as easy to grok without attaching a debugger but this makes complete sense now.
/**
* Perform the action on the given models.
*
* @param \Laravel\Nova\Fields\ActionFields $fields
* @param \Illuminate\Support\Collection $models
* @return mixed
*/
public function handle(ActionFields $fields, Collection $models)
{
$count = 1;
foreach ($models as $model) {
$count = $this->generateCodes($model->id, $model->code_type_id, $fields->number);
}
return Action::message("$count codes were successfully created.");
}
Sat Jun 29
.gitignore
for VSCode integration and to remove /config/*.secret.exs
. It's unclear if this was present in the earlier version of Phoenix and I weirdly need to add it. It's also possible that I just followed along with the up and running guide.Wed June 26
How Laravel prevents your scheduled jobs from overlapping - Diving Laravel
obr-sage-sync
scheduler was broken in production due to network outages affecting Digital Ocean droplets. The sync:customers
command would not execute via the scheduler because withoutOverlap()
detected the command was still executing.Fri Jun 28
Started over with Phoenix 1.4.8 using asdf global packages for the following:
elixir 1.9.0 (set by /Users/jbrayton/.tool-versions)
erlang 22.0.4 (set by /Users/jbrayton/.tool-versions)
nodejs 12.5.0 (set by /Users/jbrayton/.tool-versions)
Essentially, I changed the shim for node to:
#!/usr/bin/env bash
# asdf-plugin: nodejs 10.15.3
# asdf-plugin: nodejs 8.11.4
# asdf-plugin: nodejs 12.5.0
exec $(brew --prefix asdf)/bin/asdf exec "npm" "$@"
/usr/local/opt/asdf/bin/asdf
and seems to work for the other packages. It could be that I was trying to do a local install before a global.Mon Jun 10
Returning files sorted by creation time.
$files = collect(\File::files($realDirectory))
->filter(function(\SplFileInfo $file) {
return strpos($file->getFileName(), "{$this->fileName}");
})->sortBy(function (\SplFileInfo $file) {
return $file->getCTime();
}, SORT_NUMERIC)->map(function (\SplFileInfo $file) {
return [
'base' => $file->getBasename(),
'name' => $file->getFilename(),
'created' => $file->getCTime(),
'modified' => $file->getMTime(),
'size' => $file->getSize(),
];
});
Fri June 14
Needed to get directories from my dotfiles using yadm as the PHPStorm license was no longer active.
yadm log --all --full-history -- **/thefile.*
Thu Apr 18
Numbers
2 / 2 = 1.0
? Division seems to coerce to floatsdiv()
returns the divisor or 2, not 2.5. It's an integerrem()
returns the remainder or 1, not 0.5. The .5 is dividing the remainder by 2.(2 * 2.0) = 4.0
as the types coerce the resultFloat.round(1.2) === round(1.2) == false
Individual digits builds an array, not count of digits.
Integer.parse
returns the unparsable part as a string ".2"
Float.ciel
seems to round > 0 up to the next integer, even 0.25
Tuples
List.delete_at
is zero-based or more importantly pretty much all these methods are zero based to match array indexesKeyword Lists koan.
foo:
like json but the tuple reads :foo
{:foo , "bar"}
Needs the space after :foo
Mon Mar 25
Specifically using JSON fields as virtual calculations versus setting an explicit string/integer field and filling it in that way. This way we only store the JSON and the rest is done for us.
Wed Mar 27
Highlighting the method name like Integer.is_odd gives the definition (hell yes).
Wed Mar 20
Initially tried using my elixir version but ran into minor issues
mix.lock
due to differences in runtime.Prepped git repository for common changes and using a feature/pass_1
branch to show our first pass.
Erlang/OTP 21 [erts-10.2.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Elixir 1.8.1 (compiled with Erlang/OTP 21)
Mon Feb 25
.gitignore
for VSCode integrationTue Feb 26
mix phx.gen.cert
Added self-signed port to dev config
Changed medicine route to a resource. Added show method and initial view.
<%= @medicine.id %>
syntax. The key is the @ symbol.Added title from layout view. Will want to make it Supple - Page dynamically as you move about the app