@algolia/wizard 0.9.0-rc.78.68 → 0.9.0-rc.80.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -1003,7 +1003,7 @@ var accessItems = [
1003
1003
  {
1004
1004
  tag: "READ",
1005
1005
  title: "Project files",
1006
- description: "reads your dependency manifests (package.json, pyproject.toml, Gemfile, go.mod\u2026), configs & source to detect your stack. Read-only; nothing is uploaded."
1006
+ description: "reads your dependency manifests (package.json, pyproject.toml, Gemfile, go.mod, pom.xml\u2026), configs & source to detect your stack. Read-only; nothing is uploaded."
1007
1007
  },
1008
1008
  {
1009
1009
  tag: "WRITE",
@@ -2266,6 +2266,7 @@ function shellQuote(value) {
2266
2266
  // src/lib/languages.ts
2267
2267
  var ENTRYPOINT_TOKEN = "{entrypoint}";
2268
2268
  var INGEST_DIR = ".algolia-wizard";
2269
+ var CSHARP_PROJECT = `${INGEST_DIR}/ingest/ingest.csproj`;
2269
2270
  var VISIBLE_INGEST_DIR = "algolia-wizard";
2270
2271
  var PY_VENV = `${INGEST_DIR}/.venv`;
2271
2272
  var PY_VENV_PYTHON = `${PY_VENV}/bin/python`;
@@ -2489,6 +2490,193 @@ var LANGUAGE_PROFILES = {
2489
2490
  ],
2490
2491
  envReadInstruction: "Read them from `os.Getenv`.",
2491
2492
  skipDirs: ["vendor", "bin"]
2493
+ },
2494
+ java: {
2495
+ id: "java",
2496
+ displayName: "Java",
2497
+ aliases: ["java"],
2498
+ manifests: ["pom.xml", "build.gradle", "build.gradle.kts"],
2499
+ packageManagers: [
2500
+ {
2501
+ id: "maven",
2502
+ detectFiles: ["pom.xml"],
2503
+ sdkVersionPin: "[4,5)",
2504
+ dependency: { mode: "agent-declares", file: "pom.xml" },
2505
+ installSteps: [{ argv: ["mvn", "-q", "-DskipTests", "compile"] }],
2506
+ // The main class is a wizard constant the instructions require the agent
2507
+ // to use, so execution can't be redirected by agent output. Runnable only
2508
+ // because the install step above compiles src/main/java first — which is
2509
+ // why the entrypoint lives there rather than under .algolia-wizard/.
2510
+ ingest: {
2511
+ kind: "auto",
2512
+ argv: [
2513
+ "mvn",
2514
+ "-q",
2515
+ "org.codehaus.mojo:exec-maven-plugin:3.5.0:java",
2516
+ "-Dexec.mainClass=AlgoliaWizardIngest"
2517
+ ],
2518
+ entrypointExtensions: [".java"]
2519
+ }
2520
+ },
2521
+ {
2522
+ id: "gradle",
2523
+ detectFiles: ["build.gradle", "build.gradle.kts"],
2524
+ dependency: {
2525
+ mode: "agent-declares",
2526
+ file: "build.gradle",
2527
+ alternatives: ["build.gradle.kts"]
2528
+ },
2529
+ installSteps: [],
2530
+ // Auto-running means executing the repo's own ./gradlew wrapper; out of
2531
+ // scope for now, so the wizard writes the code and prints the command.
2532
+ ingest: {
2533
+ kind: "manual",
2534
+ entrypointExtensions: [".java"],
2535
+ runCommand: "./gradlew runAlgoliaIngest",
2536
+ requiresBuildTask: "runAlgoliaIngest"
2537
+ }
2538
+ }
2539
+ ],
2540
+ sdk: {
2541
+ packageName: "com.algolia:algoliasearch",
2542
+ versionPin: "4.+",
2543
+ docKey: "java",
2544
+ alsoRequires: "The class must be named AlgoliaWizardIngest, in the default package (no `package` statement), with a `public static void main`."
2545
+ },
2546
+ // Not under .algolia-wizard/: Maven and Gradle only compile src/main/<lang>,
2547
+ // so a class outside it never makes it onto the classpath and the run command
2548
+ // fails with "class not found".
2549
+ ingestEntrypointExample: "src/main/java/AlgoliaWizardIngest.java",
2550
+ verification: [
2551
+ {
2552
+ label: "mvn compile",
2553
+ argv: ["mvn", "-q", "-DskipTests", "compile"],
2554
+ requiresFile: "pom.xml"
2555
+ }
2556
+ ],
2557
+ envReadInstruction: "Read them from `System.getenv`.",
2558
+ skipDirs: ["target", "build", "out"]
2559
+ },
2560
+ kotlin: {
2561
+ id: "kotlin",
2562
+ displayName: "Kotlin",
2563
+ aliases: ["kotlin", "kt", "ktor"],
2564
+ manifests: ["build.gradle.kts", "build.gradle", "pom.xml"],
2565
+ packageManagers: [
2566
+ {
2567
+ id: "gradle",
2568
+ detectFiles: ["build.gradle.kts", "build.gradle"],
2569
+ dependency: {
2570
+ mode: "agent-declares",
2571
+ file: "build.gradle.kts",
2572
+ alternatives: ["build.gradle"]
2573
+ },
2574
+ installSteps: [],
2575
+ ingest: {
2576
+ kind: "manual",
2577
+ entrypointExtensions: [".kt"],
2578
+ runCommand: "./gradlew runAlgoliaIngest",
2579
+ requiresBuildTask: "runAlgoliaIngest"
2580
+ }
2581
+ },
2582
+ // Kotlin/Maven is rare but real, and pom.xml is a Kotlin manifest — without
2583
+ // this spec such a repo falls through to Gradle and is told to run a
2584
+ // ./gradlew task that doesn't exist. Compiling needs the repo's own
2585
+ // kotlin-maven-plugin, so the run stays the developer's step.
2586
+ {
2587
+ id: "maven",
2588
+ detectFiles: ["pom.xml"],
2589
+ sdkVersionPin: "[3,4)",
2590
+ dependency: { mode: "agent-declares", file: "pom.xml" },
2591
+ installSteps: [{ argv: ["mvn", "-q", "-DskipTests", "compile"] }],
2592
+ ingest: {
2593
+ kind: "manual",
2594
+ entrypointExtensions: [".kt"],
2595
+ runCommand: "mvn -q org.codehaus.mojo:exec-maven-plugin:3.5.0:java -Dexec.mainClass=AlgoliaWizardIngest"
2596
+ }
2597
+ }
2598
+ ],
2599
+ sdk: {
2600
+ packageName: "com.algolia:algoliasearch-client-kotlin",
2601
+ versionPin: "3.+",
2602
+ docKey: "kotlin",
2603
+ // The published client's commonMain ships only ktor-client-core; without an
2604
+ // engine the script compiles and then fails at its first request.
2605
+ alsoRequires: "The Kotlin client bundles no HTTP engine, so also declare one (e.g. io.ktor:ktor-client-okhttp). Name the object AlgoliaWizardIngest in the default package, with a @JvmStatic main."
2606
+ },
2607
+ ingestEntrypointExample: "src/main/kotlin/AlgoliaWizardIngest.kt",
2608
+ verification: [],
2609
+ envReadInstruction: "Read them from `System.getenv`.",
2610
+ skipDirs: ["build", "out"]
2611
+ },
2612
+ scala: {
2613
+ id: "scala",
2614
+ displayName: "Scala",
2615
+ aliases: ["scala", "sbt"],
2616
+ manifests: ["build.sbt", "build.sc"],
2617
+ packageManagers: [
2618
+ {
2619
+ id: "sbt",
2620
+ dependency: { mode: "agent-declares", file: "build.sbt" },
2621
+ installSteps: [],
2622
+ ingest: {
2623
+ kind: "manual",
2624
+ entrypointExtensions: [".scala"],
2625
+ runCommand: 'sbt "runMain AlgoliaWizardIngest"'
2626
+ }
2627
+ }
2628
+ ],
2629
+ sdk: {
2630
+ packageName: "com.algolia:algoliasearch-scala_2.13",
2631
+ versionPin: "2.+",
2632
+ docKey: "scala",
2633
+ alsoRequires: "Name the object AlgoliaWizardIngest in the default package (no `package` statement) so `runMain AlgoliaWizardIngest` resolves it."
2634
+ },
2635
+ ingestEntrypointExample: "src/main/scala/AlgoliaWizardIngest.scala",
2636
+ verification: [],
2637
+ envReadInstruction: "Read them from `sys.env`.",
2638
+ // `project/` holds sbt's build definition, but the name is generic enough
2639
+ // that some repos use it for source; scanning it is cheap, missing source
2640
+ // is not.
2641
+ skipDirs: ["target"]
2642
+ },
2643
+ csharp: {
2644
+ id: "csharp",
2645
+ displayName: "C#",
2646
+ aliases: ["c#", "csharp", "cs", ".net", "dotnet", "net", "asp.net"],
2647
+ manifests: ["*.csproj", "*.sln", "global.json"],
2648
+ packageManagers: [
2649
+ {
2650
+ id: "dotnet",
2651
+ // A self-contained project under .algolia-wizard keeps the ingest script
2652
+ // out of the repo's own build graph.
2653
+ dependency: { mode: "agent-declares", file: CSHARP_PROJECT },
2654
+ installSteps: [{ argv: ["dotnet", "restore", CSHARP_PROJECT] }],
2655
+ ingest: {
2656
+ kind: "auto",
2657
+ argv: ["dotnet", "run", "--project", ENTRYPOINT_TOKEN],
2658
+ entrypointExtensions: [".csproj"]
2659
+ }
2660
+ }
2661
+ ],
2662
+ sdk: {
2663
+ packageName: "Algolia.Search",
2664
+ versionPin: "7.*",
2665
+ docKey: "csharp"
2666
+ },
2667
+ ingestEntrypointExample: CSHARP_PROJECT,
2668
+ verification: [
2669
+ {
2670
+ label: "dotnet build",
2671
+ argv: ["dotnet", "build", CSHARP_PROJECT, "--nologo"],
2672
+ requiresFile: CSHARP_PROJECT
2673
+ }
2674
+ ],
2675
+ envReadInstruction: 'Read them from `Environment.GetEnvironmentVariable("NAME")`.',
2676
+ // Deliberately not `packages`: modern .NET uses PackageReference, and
2677
+ // `packages/` is where pnpm/Lerna/Turborepo monorepos keep all their source —
2678
+ // skipping it would hide the entities the scan is looking for.
2679
+ skipDirs: ["bin", "obj"]
2492
2680
  }
2493
2681
  };
2494
2682
  var DEFAULT_LANGUAGE_ID = "javascript";
@@ -3171,9 +3359,9 @@ var detectLanguageSchema = z16.object({
3171
3359
  var detectLanguage = () => runAgent({
3172
3360
  instructions: [
3173
3361
  "Analyze the codebase and determine the programming languages and frameworks used",
3174
- "Start from the dependency manifests: package.json, pyproject.toml, requirements.txt, Gemfile, composer.json, go.mod.",
3362
+ "Start from the dependency manifests: package.json, pyproject.toml, requirements.txt, Gemfile, composer.json, go.mod, pom.xml, build.gradle(.kts), *.csproj, build.sbt.",
3175
3363
  "List the language that owns the backend/data code first \u2014 that is the one an ingestion script will be written in.",
3176
- "If a superset language is found, exclude the subset language. TS-over-JS.",
3364
+ "If a superset language is found, exclude the subset language. TS-over-JS. Kotlin-over-Java when Kotlin is primary.",
3177
3365
  "If a meta-framework is used, exclude the framework. Next-over-React.",
3178
3366
  "Frameworks include backend and server-rendering frameworks (e.g. Rails, Django, Laravel, Symfony, Spring Boot, ASP.NET Core, Flask, Gin, Ktor) as well as frontend ones (React, Vue, Angular, Svelte) and mobile ones (Flutter, SwiftUI).",
3179
3367
  "Return the exact version",
@@ -3224,7 +3412,7 @@ var MODE_CONFIG = {
3224
3412
  "Analyze the codebase to find the data entities (models) that should be ingested into Algolia.",
3225
3413
  "For each entity, return its name, the file path(s) where it is defined, and its indexable attribute keys (the fields a user would search or filter on).",
3226
3414
  "Inspect the source of each entity to extract real field names for attributes \u2014 do not guess or leave attributes empty.",
3227
- "Entities live wherever the stack keeps them: TypeScript interfaces or a Prisma schema, Django models.py, Rails app/models, Laravel Eloquent models, Go structs, Pydantic models.",
3415
+ "Entities live wherever the stack keeps them: TypeScript interfaces or a Prisma schema, Django models.py, Rails app/models, Laravel Eloquent models, JPA @Entity classes, Go structs, C# entity classes, Pydantic models.",
3228
3416
  "Prefer domain models (e.g. Document, Product, User) over framework or infrastructure types.",
3229
3417
  "Use as few tools as possible, but do not guess. If you cannot find any entities, return an empty array.",
3230
3418
  "Ignore directories that may be related to testing, like `/fixtures`, `/tests`, etc",
@@ -3247,7 +3435,7 @@ var MODE_CONFIG = {
3247
3435
  verification: {
3248
3436
  instructions: [
3249
3437
  "Analyze the codebase to determine which code-quality tools are available to validate changes.",
3250
- "Look at the dependency manifest and config files for the project's languages: package.json scripts with tsconfig/eslint/prettier, pyproject.toml or setup.cfg (ruff, mypy, black), Gemfile with .rubocop.yml, composer.json scripts (phpstan, pint), go.mod with a golangci-lint config.",
3438
+ "Look at the dependency manifest and config files for the project's languages: package.json scripts with tsconfig/eslint/prettier, pyproject.toml or setup.cfg (ruff, mypy, black), Gemfile with .rubocop.yml, composer.json scripts (phpstan, pint), go.mod with a golangci-lint config, Maven/Gradle verification tasks, .NET analyzers.",
3251
3439
  'Return the tool names as an array, e.g. ["eslint", "prettier", "tsc"] or ["ruff", "mypy"].',
3252
3440
  "Use as few tools as possible, but do not guess. If you cannot find any, return an empty array.",
3253
3441
  "Ignore directories that may be related to testing, like `/fixtures`, `/tests`, etc",
@@ -3275,7 +3463,7 @@ async function runAnalysis(mode, extraInstructions = []) {
3275
3463
  // package.json
3276
3464
  var package_default = {
3277
3465
  name: "@algolia/wizard",
3278
- version: "0.9.0-rc.78.68",
3466
+ version: "0.9.0-rc.80.70",
3279
3467
  description: "Magically implement Algolia functionality in your codebase",
3280
3468
  type: "module",
3281
3469
  engines: {
@@ -3741,7 +3929,7 @@ ${JSON.stringify(s.output, null, 2)}`
3741
3929
  }
3742
3930
  function formatReviewSummary(result) {
3743
3931
  const nextStepLines = result.nextSteps.map((step) => {
3744
- const isIngestCommand = step.includes("algolia-wizard/");
3932
+ const isIngestCommand = step.includes("algolia-wizard/") || step.includes("AlgoliaWizardIngest");
3745
3933
  const isWorktreeCommand = step.includes("/worktrees/");
3746
3934
  return {
3747
3935
  text: `\u2192 ${step}`,
@@ -20,6 +20,10 @@ Install the latest stable within the major; never pin an exact patch.
20
20
  | Ruby | `algolia` | `~> 3.0` |
21
21
  | PHP | `algolia/algoliasearch-client-php` | `^4` |
22
22
  | Go | `github.com/algolia/algoliasearch-client-go/v4` | `v4` |
23
+ | Java | `com.algolia:algoliasearch` | `4.+` |
24
+ | Kotlin | `com.algolia:algoliasearch-client-kotlin` | `3.+` |
25
+ | Scala | `com.algolia:algoliasearch-scala_2.13` | `2.+` |
26
+ | C# | `Algolia.Search` | `7.*` |
23
27
 
24
28
  ## Search UI
25
29
 
@@ -0,0 +1,71 @@
1
+ # Save records (Algolia.Search v7)
2
+
3
+ Adds records to an index. Write op — use a **write key**, server-side only.
4
+
5
+ The generated script is a self-contained console project at
6
+ `.algolia-wizard/ingest/ingest.csproj` + `Program.cs`, run with
7
+ `dotnet run --project .algolia-wizard/ingest/ingest.csproj`.
8
+
9
+ ```xml
10
+ <Project Sdk="Microsoft.NET.Sdk">
11
+ <PropertyGroup>
12
+ <OutputType>Exe</OutputType>
13
+ <TargetFramework>net8.0</TargetFramework>
14
+ <ImplicitUsings>enable</ImplicitUsings>
15
+ <Nullable>enable</Nullable>
16
+ </PropertyGroup>
17
+ <ItemGroup>
18
+ <PackageReference Include="Algolia.Search" Version="7.*" />
19
+ </ItemGroup>
20
+ </Project>
21
+ ```
22
+
23
+ `<OutputType>Exe</OutputType>` is required — `dotnet run` on a library has no entry
24
+ point. `<TargetFramework>` must match an installed SDK; `net8.0` (LTS) is the safe
25
+ default. Under Central Package Management (`Directory.Packages.props` at the repo
26
+ root) omit `Version` here and pin it there — `Version` on a `PackageReference` is
27
+ an error under CPM (NU1008).
28
+
29
+ ```csharp
30
+ using System.Text.Json;
31
+ using Algolia.Search.Clients;
32
+
33
+ var appId = Environment.GetEnvironmentVariable("ALGOLIA_APPLICATION_ID")
34
+ ?? throw new InvalidOperationException("ALGOLIA_APPLICATION_ID is not set");
35
+ var writeKey = Environment.GetEnvironmentVariable("ALGOLIA_WRITE_API_KEY")
36
+ ?? throw new InvalidOperationException("ALGOLIA_WRITE_API_KEY is not set");
37
+
38
+ var client = new SearchClient(new SearchConfig(appId, writeKey));
39
+ var indexName = "products";
40
+
41
+ var records = new List<Dictionary<string, object>>
42
+ {
43
+ new() { ["objectID"] = "1", ["name"] = "Adam" },
44
+ new() { ["objectID"] = "2", ["name"] = "Benoit" },
45
+ };
46
+
47
+ var responses = await client.SaveObjectsAsync(indexName, records, waitForTasks: true);
48
+ ```
49
+
50
+ ```csharp
51
+ Task<List<BatchResponse>> SaveObjectsAsync<T>(
52
+ string indexName, IEnumerable<T> objects, bool waitForTasks = false,
53
+ int batchSize = 1000, RequestOptions options = null,
54
+ CancellationToken cancellationToken = default) where T : class;
55
+ ```
56
+
57
+ Records need an `objectID`; batching in 1,000s is automatic. Returns
58
+ `List<BatchResponse>` — one entry per batch, each `{ TaskID, ObjectIDs }`, never a
59
+ single response. `T` is constrained to `class`, so use `Dictionary<string, object>`
60
+ or a record/class, never a struct.
61
+
62
+ Read records from a JSON file:
63
+
64
+ ```csharp
65
+ var json = await File.ReadAllTextAsync("records.json");
66
+ var records = JsonSerializer.Deserialize<List<Dictionary<string, object>>>(json)
67
+ ?? new List<Dictionary<string, object>>();
68
+ ```
69
+
70
+ After a successful ingest, print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` as the last
71
+ stdout line; send all other logging to stderr so nothing follows it on stdout.
@@ -0,0 +1,66 @@
1
+ # Save records (algoliasearch Java v4)
2
+
3
+ Adds records to an index. Write op — use a **write key**, server-side only.
4
+
5
+ ```xml
6
+ <dependency>
7
+ <groupId>com.algolia</groupId>
8
+ <artifactId>algoliasearch</artifactId>
9
+ <version>4.20.0</version>
10
+ </dependency>
11
+ ```
12
+
13
+ ```groovy
14
+ implementation 'com.algolia:algoliasearch:4.20.0'
15
+ ```
16
+
17
+ The class MUST be `AlgoliaWizardIngest` with a `public static void main`, in the
18
+ **default package** (no `package` statement) — the wizard runs a fixed main class.
19
+
20
+ ```java
21
+ import com.algolia.api.SearchClient;
22
+ import java.util.List;
23
+ import java.util.Map;
24
+
25
+ public class AlgoliaWizardIngest {
26
+
27
+ public static void main(String[] args) throws Exception {
28
+ String indexName = "products";
29
+ List<Map<String, Object>> records = List.of(Map.of("objectID", "1", "name", "Hot 100"));
30
+
31
+ SearchClient client =
32
+ new SearchClient(System.getenv("ALGOLIA_APPLICATION_ID"), System.getenv("ALGOLIA_WRITE_API_KEY"));
33
+ try {
34
+ client.saveObjects(indexName, records);
35
+ System.out.printf("ALGOLIA_WIZARD_RECORD_COUNT=%d%n", records.size());
36
+ } finally {
37
+ client.close(); // required: okhttp's non-daemon threads keep the JVM alive otherwise
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ Blocking API — calls return directly and throw `AlgoliaApiException` on failure.
44
+
45
+ ```java
46
+ // objects: Maps or POJOs (Jackson-serialized), each with an objectID
47
+ <T> List<BatchResponse> saveObjects(String indexName, Iterable<T> objects)
48
+ <T> List<BatchResponse> saveObjects(String indexName, Iterable<T> objects,
49
+ boolean waitForTasks, int batchSize, RequestOptions requestOptions) // batchSize default 1000
50
+ ```
51
+
52
+ One `BatchResponse` (`getTaskID()`, `getObjectIDs()`) per batch of 1,000, not per record.
53
+
54
+ Read records from a JSON file (Jackson is a transitive dependency):
55
+
56
+ ```java
57
+ import com.fasterxml.jackson.core.type.TypeReference;
58
+ import com.fasterxml.jackson.databind.ObjectMapper;
59
+ import java.io.File;
60
+
61
+ List<Map<String, Object>> records = new ObjectMapper()
62
+ .readValue(new File("records.json"), new TypeReference<List<Map<String, Object>>>() {});
63
+ ```
64
+
65
+ After a successful ingest print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` (n = records
66
+ read, not the returned list size) as the last stdout line.
@@ -0,0 +1,60 @@
1
+ # Save records (algoliasearch-client-kotlin v3)
2
+
3
+ Adds records to an index. Write op — use a **write key**, server-side only.
4
+
5
+ Gradle Kotlin DSL. The client ships only `ktor-client-core`, so a JVM engine must
6
+ be declared too or the first call fails with no HTTP engine found:
7
+
8
+ ```kotlin
9
+ implementation("com.algolia:algoliasearch-client-kotlin:3.23.0")
10
+ implementation("io.ktor:ktor-client-okhttp:3.2.0")
11
+ ```
12
+
13
+ `saveObjects` is a `suspend` extension, so a standalone script wraps it in
14
+ `runBlocking`. The object MUST be `AlgoliaWizardIngest` in the **default package**
15
+ (no `package` statement), and `@JvmStatic` is required — a `fun main` inside an
16
+ object is not a JVM entrypoint without it.
17
+
18
+ ```kotlin
19
+ import com.algolia.client.api.SearchClient
20
+ import com.algolia.client.extensions.*
21
+ import java.io.File
22
+ import kotlinx.coroutines.runBlocking
23
+ import kotlinx.serialization.json.*
24
+
25
+ object AlgoliaWizardIngest {
26
+ @JvmStatic
27
+ fun main(args: Array<String>): Unit = runBlocking {
28
+ val indexName = "products"
29
+ val records: List<JsonObject> = listOf(buildJsonObject { put("objectID", "1"); put("name", "Hot 100") })
30
+
31
+ // System.getenv returns String?; the constructor params are non-null
32
+ SearchClient(
33
+ appId = requireNotNull(System.getenv("ALGOLIA_APPLICATION_ID")),
34
+ apiKey = requireNotNull(System.getenv("ALGOLIA_WRITE_API_KEY")),
35
+ ).use { client -> // AutoCloseable: without use/close, okhttp's non-daemon threads hang the JVM
36
+ client.saveObjects(indexName = indexName, objects = records)
37
+ println("ALGOLIA_WIZARD_RECORD_COUNT=${records.size}")
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ```kotlin
44
+ // objects is List<JsonObject> — not arbitrary data classes; each needs an objectID
45
+ suspend fun SearchClient.saveObjects(
46
+ indexName: String, objects: List<JsonObject>, waitForTasks: Boolean = false,
47
+ batchSize: Int = 1000, requestOptions: RequestOptions? = null,
48
+ ): List<BatchResponse>
49
+ ```
50
+
51
+ One `BatchResponse` (`taskID`, `objectIDs`) per batch of 1,000, not per record.
52
+
53
+ Read records from a JSON file (no serialization plugin needed for `JsonObject`):
54
+
55
+ ```kotlin
56
+ val records = Json.parseToJsonElement(File("records.json").readText()).jsonArray.map { it.jsonObject }
57
+ ```
58
+
59
+ After a successful ingest print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` (n = records
60
+ read, not the returned list size) as the last stdout line.
@@ -0,0 +1,68 @@
1
+ # Save records (algoliasearch-scala v2)
2
+
3
+ Adds records to an index. Write op — use a **write key**, server-side only.
4
+
5
+ sbt (`%%` appends the Scala binary version, resolving to
6
+ `com.algolia:algoliasearch-scala_2.13` on Scala 2.13):
7
+
8
+ ```scala
9
+ libraryDependencies += "com.algolia" %% "algoliasearch-scala" % "2.22.0"
10
+ ```
11
+
12
+ The object MUST be `AlgoliaWizardIngest` with an explicit `main` (not `extends
13
+ App`), in the **default package** (no `package` statement) — the wizard runs
14
+ `sbt "runMain AlgoliaWizardIngest"`.
15
+
16
+ ```scala
17
+ import algoliasearch.api.SearchClient
18
+ import algoliasearch.extension.SearchClientExtensions // brings saveObjects into scope
19
+ import scala.concurrent.Await
20
+ import scala.concurrent.ExecutionContext.Implicits.global
21
+ import scala.concurrent.duration.Duration
22
+
23
+ object AlgoliaWizardIngest {
24
+ def main(args: Array[String]): Unit = {
25
+ val indexName = "products"
26
+ val records: Seq[Map[String, Any]] = Seq(Map("objectID" -> "1", "name" -> "Hot 100"))
27
+
28
+ val client = SearchClient(
29
+ appId = sys.env("ALGOLIA_APPLICATION_ID"),
30
+ apiKey = sys.env("ALGOLIA_WRITE_API_KEY")
31
+ )
32
+ try {
33
+ Await.result(client.saveObjects(indexName, records), Duration(120, "sec"))
34
+ println(s"ALGOLIA_WIZARD_RECORD_COUNT=${records.size}")
35
+ } finally client.close() // else okhttp's non-daemon threads hang the JVM
36
+ }
37
+ }
38
+ ```
39
+
40
+ Future-based API: a script must `Await.result` with a generous timeout, and an
41
+ implicit `ExecutionContext` must be in scope.
42
+
43
+ ```scala
44
+ // objects: Seq[Map[String, Any]] or case classes, each carrying an objectID
45
+ def saveObjects(indexName: String, objects: Seq[Any], waitForTasks: Boolean = false,
46
+ batchSize: Int = 1000, requestOptions: Option[RequestOptions] = None)(
47
+ implicit ec: ExecutionContext): Future[Seq[BatchResponse]]
48
+ ```
49
+
50
+ Yields one `BatchResponse` (`taskID`, `objectIDs`) per batch of 1,000, not per record.
51
+
52
+ Read records from a JSON file (json4s ships with the client):
53
+
54
+ ```scala
55
+ import algoliasearch.search.JsonSupport
56
+ import org.json4s.native.JsonMethods
57
+ import org.json4s.jvalue2extractable
58
+ import scala.io.Source
59
+ import scala.util.Using
60
+
61
+ implicit val formats: org.json4s.Formats = JsonSupport.format // required by extract
62
+ val records = JsonMethods
63
+ .parse(Using(Source.fromFile("records.json"))(_.mkString).get)
64
+ .extract[Seq[Map[String, Any]]]
65
+ ```
66
+
67
+ After a successful ingest print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` (n = records
68
+ read, not the returned `Seq` size) as the last stdout line.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.9.0-rc.78.68",
3
+ "version": "0.9.0-rc.80.70",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {