• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mithereal / ex_catalog / 95d26bd2aa9054ee526c319ea0e6b61a453cdad0

19 Nov 2023 12:27PM UTC coverage: 20.0% (-0.6%) from 20.556%
95d26bd2aa9054ee526c319ea0e6b61a453cdad0

push

github

mithereal
add manufacturer preload

72 of 360 relevant lines covered (20.0%)

0.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

39.02
/lib/ex_catalog.ex
1
defmodule ExCatalog do
2
  @moduledoc """
3
  Documentation for `ExCatalog`.
4
  """
5
  @repo ExCatalog.Config.repo()
6

7
  alias ExCatalog.Category
8
  alias ExCatalog.Product
9
  alias ExCatalog.Manufacturer
10

11
  @doc """
12
  List version.
13
  """
14
  @version Mix.Project.config()[:version]
15
  def version, do: @version
1✔
16

17
  @doc """
18
  List all the categories (the index).
19

20
  ## Examples
21

22
      iex> ExCatalog.index(25)
23

24

25
  """
26
  def index(limit \\ 25, metadata \\ nil, cursor \\ nil, deleted \\ false) do
27
    import Ecto.Query
28
    import Ecto.SoftDelete.Query
29

30
    query =
1✔
31
      case(deleted) do
32
        false ->
33
          from(ExCatalog.Category,
1✔
34
            preload: [:parent_category],
35
            preload: [:image]
36
          )
37

38
        true ->
39
          from(ExCatalog.Category,
40
            preload: [:parent_category],
41
            preload: [:image]
42
          )
43
          |> with_undeleted
×
44
      end
45

46
    case cursor do
1✔
47
      :before ->
48
        @repo.paginate(
×
49
          query,
50
          before: metadata.before,
×
51
          include_total_count: true,
52
          cursor_fields: [:inserted_at, :id],
53
          limit: limit
54
        )
55

56
      :after ->
57
        @repo.paginate(
×
58
          query,
59
          after: metadata.after,
×
60
          include_total_count: true,
61
          cursor_fields: [:inserted_at, :id],
62
          limit: limit
63
        )
64

65
      _ ->
66
        @repo.paginate(
1✔
67
          query,
68
          include_total_count: true,
69
          cursor_fields: [:inserted_at, :id],
70
          limit: limit
71
        )
72
    end
73
  end
74

75
  @doc """
76
  List all products with preloads and optional currency conversion..
77

78
  ## Examples
79

80
      iex> ExCatalog.products(25)
81
      iex> ExCatalog.products(25,:USD)
82

83

84
  """
85
  def products(limit \\ 25, currency \\ :USD, deleted \\ false, owner_id \\ nil) do
86
    products(limit, nil, nil, currency, deleted, owner_id)
3✔
87
  end
88

89
  def products(limit \\ 25, metadata, cursor, currency, deleted, owner_id) do
90
    import Ecto.Query
91
    import Ecto.SoftDelete.Query
92

93
    query =
3✔
94
      case(owner_id) do
95
        nil ->
96
          case(deleted) do
3✔
97
            false ->
98
              from(ExCatalog.Product,
3✔
99
                preload: [:variations],
100
                preload: [:categories],
101
                preload: [:metas],
102
                preload: [:primary_image],
103
                preload: [:images],
104
                preload: [:manufacturer],
105
                preload: [:videos]
106
              )
107

108
            true ->
109
              from(ExCatalog.Product,
110
                preload: [:variations],
111
                preload: [:categories],
112
                preload: [:metas],
113
                preload: [:primary_image],
114
                preload: [:images],
115
                preload: [:manufacturer],
116
                preload: [:videos]
117
              )
118
              |> with_undeleted
×
119
          end
120

121
        _ ->
122
          case(deleted) do
×
123
            false ->
124
              from(ExCatalog.Product,
×
125
                where: [owner_id: ^owner_id],
126
                preload: [:variations],
127
                preload: [:categories],
128
                preload: [:metas],
129
                preload: [:primary_image],
130
                preload: [:manufacturer],
131
                preload: [:images],
132
                preload: [:videos]
133
              )
134

135
            true ->
136
              from(ExCatalog.Product,
137
                where: [owner_id: ^owner_id],
138
                preload: [:variations],
139
                preload: [:categories],
140
                preload: [:metas],
141
                preload: [:primary_image],
142
                preload: [:manufacturer],
143
                preload: [:images],
144
                preload: [:videos]
145
              )
146
              |> with_undeleted
×
147
          end
148
      end
149

150
    reply =
3✔
151
      case cursor do
152
        :before ->
153
          @repo.paginate(
×
154
            query,
155
            before: metadata.before,
×
156
            include_total_count: true,
157
            cursor_fields: [:inserted_at, :id],
158
            limit: limit
159
          )
160

161
        :after ->
162
          @repo.paginate(
×
163
            query,
164
            after: metadata.after,
×
165
            include_total_count: true,
166
            cursor_fields: [:inserted_at, :id],
167
            limit: limit
168
          )
169

170
        _ ->
171
          @repo.paginate(
3✔
172
            query,
173
            include_total_count: true,
174
            cursor_fields: [:inserted_at, :id],
175
            limit: limit
176
          )
177
      end
178

179
    case currency do
3✔
180
      nil ->
181
        reply
×
182

183
      _ ->
184
        modified =
3✔
185
          Enum.map(reply.entries, fn x ->
3✔
186
            {:ok, price} = ExCatalog.Currencies.convert(x.price, currency)
×
187
            %{x | price: price}
×
188
          end)
189

190
        {modified, reply.metadata}
3✔
191
    end
192
  end
193

194
  @doc """
195
  List product with preloads by sku and optional currency conversion.
196

197
  ## Examples
198

199
      iex> price = Money.new(:USD, 100)
200
      iex>  product = %{sku: "12345", price: price, title: "test product", sub_title: "test product", description: "test product"}
201
      iex> ExCatalog.product(product.sku)
202

203

204
  """
205
  def product(sku, currency \\ nil, deleted \\ false) do
206
    import Ecto.Query
207
    import Ecto.SoftDelete.Query
208

209
    query =
2✔
210
      case(deleted) do
211
        false ->
212
          from(ExCatalog.Product,
2✔
213
            where: [sku: ^sku],
214
            preload: [:variations],
215
            preload: [:categories],
216
            preload: [:metas],
217
            preload: [:primary_image],
218
            preload: [:manufacturer],
219
            preload: [:images],
220
            preload: [:videos]
221
          )
222

223
        true ->
224
          from(ExCatalog.Product,
225
            where: [sku: ^sku],
226
            preload: [:variations],
227
            preload: [:categories],
228
            preload: [:metas],
229
            preload: [:primary_image],
230
            preload: [:manufacturer],
231
            preload: [:images],
232
            preload: [:videos]
233
          )
234
          |> with_undeleted
×
235
      end
236

237
    reply = @repo.all(query)
2✔
238

239
    case List.first(reply) do
2✔
240
      nil ->
241
        reply
1✔
242

243
      record ->
244
        case currency do
1✔
245
          nil ->
246
            record
×
247

248
          currency ->
249
            {:ok, price} = ExCatalog.Currencies.convert(record.price, currency)
1✔
250
            %{record | price: price}
1✔
251
        end
252
    end
253
  end
254

255
  @doc """
256
  List product with preloads by category and optional currency conversion.
257

258
  ## Examples
259
      iex> ExCatalog.products_by_category("test_category", 1, :USD, false, order_by: :sku)
260

261

262
  """
263
  def products_by_category(slug, limit \\ 25, currency \\ :USD, deleted \\ false, opts \\ []) do
264
    products_by_category(slug, limit, nil, nil, currency, deleted, opts)
1✔
265
  end
266

267
  def products_by_category(slug, limit, metadata, cursor, currency, deleted, opts) do
268
    category = @repo.get_by(Category, slug: slug)
1✔
269

270
    case category do
1✔
271
      nil ->
1✔
272
        {:error, "Invalid Category"}
273

274
      _ ->
275
        import Ecto.Query
276
        import Ecto.SoftDelete.Query
277

278
        order = Keyword.get(opts, :order) || :desc
×
279
        by = Keyword.get(opts, :order_by) || :updated_at
×
280
        order_by = [{order, by}]
×
281
        origins = Keyword.get(opts, :origins) || []
×
282

283
        query =
×
284
          case(deleted) do
285
            false ->
286
              from(p in ExCatalog.Product,
×
287
                where: p.category_id == ^category.id and p.origin not in ^origins,
×
288
                order_by: ^order_by,
289
                preload: [:variations],
290
                preload: [:categories],
291
                preload: [:metas],
292
                preload: [:primary_image],
293
                preload: [:manufacturer],
294
                preload: [:images],
295
                preload: [:videos]
296
              )
297

298
            true ->
299
              from(p in ExCatalog.Product,
300
                where: p.category_id == ^category.id and p.origin not in ^origins,
×
301
                preload: [:variations],
302
                preload: [:categories],
303
                preload: [:metas],
304
                preload: [:primary_image],
305
                preload: [:manufacturer],
306
                preload: [:images],
307
                preload: [:videos]
308
              )
309
              |> with_undeleted
×
310
          end
311

312
        reply =
×
313
          case cursor do
314
            :before ->
315
              @repo.paginate(
×
316
                query,
317
                before: metadata.before,
×
318
                include_total_count: true,
319
                cursor_fields: [:inserted_at, :id],
320
                limit: limit
321
              )
322

323
            :after ->
324
              @repo.paginate(
×
325
                query,
326
                after: metadata.after,
×
327
                include_total_count: true,
328
                cursor_fields: [:inserted_at, :id],
329
                limit: limit
330
              )
331

332
            _ ->
333
              @repo.paginate(
×
334
                query,
335
                include_total_count: true,
336
                cursor_fields: [:inserted_at, :id],
337
                limit: limit
338
              )
339
          end
340

341
        case currency do
×
342
          nil ->
343
            reply
×
344

345
          _ ->
346
            modified =
×
347
              Enum.map(reply.entries, fn x ->
×
348
                {:ok, price} = ExCatalog.Currencies.convert(x.price, currency)
×
349
                %{x | price: price}
×
350
              end)
351

352
            {modified, reply.metadata}
×
353
        end
354
    end
355
  end
356

357
  ###
358
  @doc """
359
  List product with preloads by country and optional currency conversion.
360

361
  ## Examples
362

363
      iex> ExCatalog.products_by_country(["US"], 2, :USD, false, order_by: :sku)
364

365

366
  """
367
  def products_by_country(origin, limit \\ 25, currency \\ :USD, deleted \\ false, opts \\ [])
×
368
      when is_list(origin) do
369
    products_by_country(origin, limit, nil, nil, currency, deleted, opts)
1✔
370
  end
371

372
  def products_by_country(origin, limit, metadata, cursor, currency, deleted, opts) do
373
    import Ecto.Query
374
    import Ecto.SoftDelete.Query
375

376
    order = Keyword.get(opts, :order) || :desc
1✔
377
    by = Keyword.get(opts, :order_by) || :updated_at
1✔
378
    order_by = [{order, by}]
1✔
379

380
    query =
1✔
381
      case(deleted) do
382
        false ->
383
          from(p in ExCatalog.Product,
1✔
384
            where: p.origin not in ^origin,
385
            order_by: ^order_by,
386
            preload: [:variations],
387
            preload: [:categories],
388
            preload: [:metas],
389
            preload: [:primary_image],
390
            preload: [:manufacturer],
391
            preload: [:images],
392
            preload: [:videos]
393
          )
394

395
        true ->
396
          from(p in ExCatalog.Product,
397
            where: p.origin not in ^origin,
398
            preload: [:variations],
399
            preload: [:categories],
400
            preload: [:metas],
401
            preload: [:primary_image],
402
            preload: [:manufacturer],
403
            preload: [:images],
404
            preload: [:videos]
405
          )
406
          |> with_undeleted
×
407
      end
408

409
    reply =
1✔
410
      case cursor do
411
        :before ->
412
          @repo.paginate(
×
413
            query,
414
            before: metadata.before,
×
415
            include_total_count: true,
416
            cursor_fields: [:inserted_at, :id],
417
            limit: limit
418
          )
419

420
        :after ->
421
          @repo.paginate(
×
422
            query,
423
            after: metadata.after,
×
424
            include_total_count: true,
425
            cursor_fields: [:inserted_at, :id],
426
            limit: limit
427
          )
428

429
        _ ->
430
          @repo.paginate(
1✔
431
            query,
432
            include_total_count: true,
433
            cursor_fields: [:inserted_at, :id],
434
            limit: limit
435
          )
436
      end
437

438
    case currency do
1✔
439
      nil ->
440
        reply
×
441

442
      _ ->
443
        modified =
1✔
444
          Enum.map(reply.entries, fn x ->
1✔
445
            {:ok, price} = ExCatalog.Currencies.convert(x.price, currency)
×
446
            %{x | price: price}
×
447
          end)
448

449
        {modified, reply.metadata}
1✔
450
    end
451
  end
452

453
  @doc """
454
  List product with preloads by manufacturer and optional currency conversion.
455

456
  ## Examples
457

458
      iex> ExCatalog.products_by_manufacturer("test_manufacturer", 2, :USD, false, order_by: :sku)
459

460

461
  """
462

463
  def products_by_manufacturer(slug, limit \\ 25, currency \\ :USD, deleted \\ false, opts \\ []) do
464
    products_by_manufacturer(slug, limit, nil, nil, currency, deleted, opts)
1✔
465
  end
466

467
  def products_by_manufacturer(slug, limit, metadata, cursor, currency, deleted, opts) do
468
    manufacturer = @repo.get_by(Manufacturer, slug: slug)
1✔
469

470
    case manufacturer do
1✔
471
      nil ->
1✔
472
        {:error, "Invalid Manufacturer"}
473

474
      _ ->
475
        import Ecto.Query
476
        import Ecto.SoftDelete.Query
477

478
        order = Keyword.get(opts, :order) || :desc
×
479
        by = Keyword.get(opts, :order_by) || :updated_at
×
480
        order_by = [{order, by}]
×
481

482
        query =
×
483
          case(deleted) do
484
            false ->
485
              from(ExCatalog.Product,
×
486
                where: [manufacturer: ^manufacturer],
487
                order_by: ^order_by,
488
                preload: [:variations],
489
                preload: [:categories],
490
                preload: [:metas],
491
                preload: [:primary_image],
492
                preload: [:manufacturer],
493
                preload: [:images],
494
                preload: [:videos]
495
              )
496

497
            true ->
498
              from(ExCatalog.Product,
499
                where: [manufacturer: ^manufacturer],
500
                preload: [:variations],
501
                preload: [:categories],
502
                preload: [:metas],
503
                preload: [:primary_image],
504
                preload: [:manufacturer],
505
                preload: [:images],
506
                preload: [:videos]
507
              )
508
              |> with_undeleted
×
509
          end
510

511
        reply =
×
512
          case cursor do
513
            :before ->
514
              @repo.paginate(
×
515
                query,
516
                before: metadata.before,
×
517
                include_total_count: true,
518
                cursor_fields: [:inserted_at, :id],
519
                limit: limit
520
              )
521

522
            :after ->
523
              @repo.paginate(
×
524
                query,
525
                after: metadata.after,
×
526
                include_total_count: true,
527
                cursor_fields: [:inserted_at, :id],
528
                limit: limit
529
              )
530

531
            _ ->
532
              @repo.paginate(
×
533
                query,
534
                include_total_count: true,
535
                cursor_fields: [:inserted_at, :id],
536
                limit: limit
537
              )
538
          end
539

540
        case currency do
×
541
          nil ->
542
            reply
×
543

544
          _ ->
545
            modified =
×
546
              Enum.map(reply.entries, fn x ->
×
547
                {:ok, price} = ExCatalog.Currencies.convert(x.price, currency)
×
548
                %{x | price: price}
×
549
              end)
550

551
            {modified, reply.metadata}
×
552
        end
553
    end
554
  end
555

556
  ###
557
  @doc """
558
  Change the status active or disabled, this controls which products the user can see, (by default only the active products are displayed)
559

560
  ## Examples
561

562
      iex>  id = Ecto.UUID.generate
563
      iex> ExCatalog.active(:category, id)
564
      iex> ExCatalog.active(:product, id)
565

566

567
  """
568
  def active(type, id) do
569
    import Ecto.Query
570
    import Ecto.SoftDelete.Query
571

572
    query =
2✔
573
      case type do
574
        :category ->
575
          from(c in Category, where: c.id == ^id, select: c)
576
          |> with_undeleted
1✔
577

578
        _ ->
579
          from(p in Product, where: p.id == ^id, select: p)
580
          |> with_undeleted
1✔
581
      end
582

583
    case Keyword.has_key?(@repo.__info__(:functions), :soft_restore!) do
2✔
584
      true ->
585
        try do
×
586
          @repo.one!(query)
587
          |> @repo.soft_restore!()
×
588
        rescue
589
          _ -> {:error, "Not Available"}
×
590
        end
591

592
      false ->
2✔
593
        {:error, "Not Available"}
594
    end
595
  end
596

597
  def active(type, id, false) do
598
    import Ecto.Query
599

600
    case type do
×
601
      :category ->
602
        @repo.get_by!(Category, id: id)
×
603

604
        from(c in Category, where: c.id == ^id, select: c)
605
        |> @repo.soft_delete!()
×
606

607
      _ ->
608
        from(p in Product, where: p.id == ^id, select: p)
609
        |> @repo.soft_delete!()
×
610
    end
611
  end
612
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc