@algolia/wizard 0.8.0-rc.63.52 → 0.8.0-rc.65.53
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 +195 -7
- package/docs/algolia-sdk/README.md +4 -0
- package/docs/algolia-sdk/save-records-csharp.md +71 -0
- package/docs/algolia-sdk/save-records-java.md +66 -0
- package/docs/algolia-sdk/save-records-kotlin.md +60 -0
- package/docs/algolia-sdk/save-records-scala.md +68 -0
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -907,7 +907,7 @@ var accessItems = [
|
|
|
907
907
|
{
|
|
908
908
|
tag: "READ",
|
|
909
909
|
title: "Project files",
|
|
910
|
-
description: "reads your dependency manifests (package.json, pyproject.toml, Gemfile, go.mod\u2026), configs & source to detect your stack. Read-only; nothing is uploaded."
|
|
910
|
+
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."
|
|
911
911
|
},
|
|
912
912
|
{
|
|
913
913
|
tag: "WRITE",
|
|
@@ -2206,6 +2206,7 @@ function shellQuote(value) {
|
|
|
2206
2206
|
// src/lib/languages.ts
|
|
2207
2207
|
var ENTRYPOINT_TOKEN = "{entrypoint}";
|
|
2208
2208
|
var INGEST_DIR = ".algolia-wizard";
|
|
2209
|
+
var CSHARP_PROJECT = `${INGEST_DIR}/ingest/ingest.csproj`;
|
|
2209
2210
|
var VISIBLE_INGEST_DIR = "algolia-wizard";
|
|
2210
2211
|
var PY_VENV = `${INGEST_DIR}/.venv`;
|
|
2211
2212
|
var PY_VENV_PYTHON = `${PY_VENV}/bin/python`;
|
|
@@ -2429,6 +2430,193 @@ var LANGUAGE_PROFILES = {
|
|
|
2429
2430
|
],
|
|
2430
2431
|
envReadInstruction: "Read them from `os.Getenv`.",
|
|
2431
2432
|
skipDirs: ["vendor", "bin"]
|
|
2433
|
+
},
|
|
2434
|
+
java: {
|
|
2435
|
+
id: "java",
|
|
2436
|
+
displayName: "Java",
|
|
2437
|
+
aliases: ["java"],
|
|
2438
|
+
manifests: ["pom.xml", "build.gradle", "build.gradle.kts"],
|
|
2439
|
+
packageManagers: [
|
|
2440
|
+
{
|
|
2441
|
+
id: "maven",
|
|
2442
|
+
detectFiles: ["pom.xml"],
|
|
2443
|
+
sdkVersionPin: "[4,5)",
|
|
2444
|
+
dependency: { mode: "agent-declares", file: "pom.xml" },
|
|
2445
|
+
installSteps: [{ argv: ["mvn", "-q", "-DskipTests", "compile"] }],
|
|
2446
|
+
// The main class is a wizard constant the instructions require the agent
|
|
2447
|
+
// to use, so execution can't be redirected by agent output. Runnable only
|
|
2448
|
+
// because the install step above compiles src/main/java first — which is
|
|
2449
|
+
// why the entrypoint lives there rather than under .algolia-wizard/.
|
|
2450
|
+
ingest: {
|
|
2451
|
+
kind: "auto",
|
|
2452
|
+
argv: [
|
|
2453
|
+
"mvn",
|
|
2454
|
+
"-q",
|
|
2455
|
+
"org.codehaus.mojo:exec-maven-plugin:3.5.0:java",
|
|
2456
|
+
"-Dexec.mainClass=AlgoliaWizardIngest"
|
|
2457
|
+
],
|
|
2458
|
+
entrypointExtensions: [".java"]
|
|
2459
|
+
}
|
|
2460
|
+
},
|
|
2461
|
+
{
|
|
2462
|
+
id: "gradle",
|
|
2463
|
+
detectFiles: ["build.gradle", "build.gradle.kts"],
|
|
2464
|
+
dependency: {
|
|
2465
|
+
mode: "agent-declares",
|
|
2466
|
+
file: "build.gradle",
|
|
2467
|
+
alternatives: ["build.gradle.kts"]
|
|
2468
|
+
},
|
|
2469
|
+
installSteps: [],
|
|
2470
|
+
// Auto-running means executing the repo's own ./gradlew wrapper; out of
|
|
2471
|
+
// scope for now, so the wizard writes the code and prints the command.
|
|
2472
|
+
ingest: {
|
|
2473
|
+
kind: "manual",
|
|
2474
|
+
entrypointExtensions: [".java"],
|
|
2475
|
+
runCommand: "./gradlew runAlgoliaIngest",
|
|
2476
|
+
requiresBuildTask: "runAlgoliaIngest"
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
],
|
|
2480
|
+
sdk: {
|
|
2481
|
+
packageName: "com.algolia:algoliasearch",
|
|
2482
|
+
versionPin: "4.+",
|
|
2483
|
+
docKey: "java",
|
|
2484
|
+
alsoRequires: "The class must be named AlgoliaWizardIngest, in the default package (no `package` statement), with a `public static void main`."
|
|
2485
|
+
},
|
|
2486
|
+
// Not under .algolia-wizard/: Maven and Gradle only compile src/main/<lang>,
|
|
2487
|
+
// so a class outside it never makes it onto the classpath and the run command
|
|
2488
|
+
// fails with "class not found".
|
|
2489
|
+
ingestEntrypointExample: "src/main/java/AlgoliaWizardIngest.java",
|
|
2490
|
+
verification: [
|
|
2491
|
+
{
|
|
2492
|
+
label: "mvn compile",
|
|
2493
|
+
argv: ["mvn", "-q", "-DskipTests", "compile"],
|
|
2494
|
+
requiresFile: "pom.xml"
|
|
2495
|
+
}
|
|
2496
|
+
],
|
|
2497
|
+
envReadInstruction: "Read them from `System.getenv`.",
|
|
2498
|
+
skipDirs: ["target", "build", "out"]
|
|
2499
|
+
},
|
|
2500
|
+
kotlin: {
|
|
2501
|
+
id: "kotlin",
|
|
2502
|
+
displayName: "Kotlin",
|
|
2503
|
+
aliases: ["kotlin", "kt", "ktor"],
|
|
2504
|
+
manifests: ["build.gradle.kts", "build.gradle", "pom.xml"],
|
|
2505
|
+
packageManagers: [
|
|
2506
|
+
{
|
|
2507
|
+
id: "gradle",
|
|
2508
|
+
detectFiles: ["build.gradle.kts", "build.gradle"],
|
|
2509
|
+
dependency: {
|
|
2510
|
+
mode: "agent-declares",
|
|
2511
|
+
file: "build.gradle.kts",
|
|
2512
|
+
alternatives: ["build.gradle"]
|
|
2513
|
+
},
|
|
2514
|
+
installSteps: [],
|
|
2515
|
+
ingest: {
|
|
2516
|
+
kind: "manual",
|
|
2517
|
+
entrypointExtensions: [".kt"],
|
|
2518
|
+
runCommand: "./gradlew runAlgoliaIngest",
|
|
2519
|
+
requiresBuildTask: "runAlgoliaIngest"
|
|
2520
|
+
}
|
|
2521
|
+
},
|
|
2522
|
+
// Kotlin/Maven is rare but real, and pom.xml is a Kotlin manifest — without
|
|
2523
|
+
// this spec such a repo falls through to Gradle and is told to run a
|
|
2524
|
+
// ./gradlew task that doesn't exist. Compiling needs the repo's own
|
|
2525
|
+
// kotlin-maven-plugin, so the run stays the developer's step.
|
|
2526
|
+
{
|
|
2527
|
+
id: "maven",
|
|
2528
|
+
detectFiles: ["pom.xml"],
|
|
2529
|
+
sdkVersionPin: "[3,4)",
|
|
2530
|
+
dependency: { mode: "agent-declares", file: "pom.xml" },
|
|
2531
|
+
installSteps: [{ argv: ["mvn", "-q", "-DskipTests", "compile"] }],
|
|
2532
|
+
ingest: {
|
|
2533
|
+
kind: "manual",
|
|
2534
|
+
entrypointExtensions: [".kt"],
|
|
2535
|
+
runCommand: "mvn -q org.codehaus.mojo:exec-maven-plugin:3.5.0:java -Dexec.mainClass=AlgoliaWizardIngest"
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
],
|
|
2539
|
+
sdk: {
|
|
2540
|
+
packageName: "com.algolia:algoliasearch-client-kotlin",
|
|
2541
|
+
versionPin: "3.+",
|
|
2542
|
+
docKey: "kotlin",
|
|
2543
|
+
// The published client's commonMain ships only ktor-client-core; without an
|
|
2544
|
+
// engine the script compiles and then fails at its first request.
|
|
2545
|
+
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."
|
|
2546
|
+
},
|
|
2547
|
+
ingestEntrypointExample: "src/main/kotlin/AlgoliaWizardIngest.kt",
|
|
2548
|
+
verification: [],
|
|
2549
|
+
envReadInstruction: "Read them from `System.getenv`.",
|
|
2550
|
+
skipDirs: ["build", "out"]
|
|
2551
|
+
},
|
|
2552
|
+
scala: {
|
|
2553
|
+
id: "scala",
|
|
2554
|
+
displayName: "Scala",
|
|
2555
|
+
aliases: ["scala", "sbt"],
|
|
2556
|
+
manifests: ["build.sbt", "build.sc"],
|
|
2557
|
+
packageManagers: [
|
|
2558
|
+
{
|
|
2559
|
+
id: "sbt",
|
|
2560
|
+
dependency: { mode: "agent-declares", file: "build.sbt" },
|
|
2561
|
+
installSteps: [],
|
|
2562
|
+
ingest: {
|
|
2563
|
+
kind: "manual",
|
|
2564
|
+
entrypointExtensions: [".scala"],
|
|
2565
|
+
runCommand: 'sbt "runMain AlgoliaWizardIngest"'
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
],
|
|
2569
|
+
sdk: {
|
|
2570
|
+
packageName: "com.algolia:algoliasearch-scala_2.13",
|
|
2571
|
+
versionPin: "2.+",
|
|
2572
|
+
docKey: "scala",
|
|
2573
|
+
alsoRequires: "Name the object AlgoliaWizardIngest in the default package (no `package` statement) so `runMain AlgoliaWizardIngest` resolves it."
|
|
2574
|
+
},
|
|
2575
|
+
ingestEntrypointExample: "src/main/scala/AlgoliaWizardIngest.scala",
|
|
2576
|
+
verification: [],
|
|
2577
|
+
envReadInstruction: "Read them from `sys.env`.",
|
|
2578
|
+
// `project/` holds sbt's build definition, but the name is generic enough
|
|
2579
|
+
// that some repos use it for source; scanning it is cheap, missing source
|
|
2580
|
+
// is not.
|
|
2581
|
+
skipDirs: ["target"]
|
|
2582
|
+
},
|
|
2583
|
+
csharp: {
|
|
2584
|
+
id: "csharp",
|
|
2585
|
+
displayName: "C#",
|
|
2586
|
+
aliases: ["c#", "csharp", "cs", ".net", "dotnet", "net", "asp.net"],
|
|
2587
|
+
manifests: ["*.csproj", "*.sln", "global.json"],
|
|
2588
|
+
packageManagers: [
|
|
2589
|
+
{
|
|
2590
|
+
id: "dotnet",
|
|
2591
|
+
// A self-contained project under .algolia-wizard keeps the ingest script
|
|
2592
|
+
// out of the repo's own build graph.
|
|
2593
|
+
dependency: { mode: "agent-declares", file: CSHARP_PROJECT },
|
|
2594
|
+
installSteps: [{ argv: ["dotnet", "restore", CSHARP_PROJECT] }],
|
|
2595
|
+
ingest: {
|
|
2596
|
+
kind: "auto",
|
|
2597
|
+
argv: ["dotnet", "run", "--project", ENTRYPOINT_TOKEN],
|
|
2598
|
+
entrypointExtensions: [".csproj"]
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
],
|
|
2602
|
+
sdk: {
|
|
2603
|
+
packageName: "Algolia.Search",
|
|
2604
|
+
versionPin: "7.*",
|
|
2605
|
+
docKey: "csharp"
|
|
2606
|
+
},
|
|
2607
|
+
ingestEntrypointExample: CSHARP_PROJECT,
|
|
2608
|
+
verification: [
|
|
2609
|
+
{
|
|
2610
|
+
label: "dotnet build",
|
|
2611
|
+
argv: ["dotnet", "build", CSHARP_PROJECT, "--nologo"],
|
|
2612
|
+
requiresFile: CSHARP_PROJECT
|
|
2613
|
+
}
|
|
2614
|
+
],
|
|
2615
|
+
envReadInstruction: 'Read them from `Environment.GetEnvironmentVariable("NAME")`.',
|
|
2616
|
+
// Deliberately not `packages`: modern .NET uses PackageReference, and
|
|
2617
|
+
// `packages/` is where pnpm/Lerna/Turborepo monorepos keep all their source —
|
|
2618
|
+
// skipping it would hide the entities the scan is looking for.
|
|
2619
|
+
skipDirs: ["bin", "obj"]
|
|
2432
2620
|
}
|
|
2433
2621
|
};
|
|
2434
2622
|
var DEFAULT_LANGUAGE_ID = "javascript";
|
|
@@ -3111,9 +3299,9 @@ var detectLanguageSchema = z16.object({
|
|
|
3111
3299
|
var detectLanguage = () => runAgent({
|
|
3112
3300
|
instructions: [
|
|
3113
3301
|
"Analyze the codebase and determine the programming languages and frameworks used",
|
|
3114
|
-
"Start from the dependency manifests: package.json, pyproject.toml, requirements.txt, Gemfile, composer.json, go.mod.",
|
|
3302
|
+
"Start from the dependency manifests: package.json, pyproject.toml, requirements.txt, Gemfile, composer.json, go.mod, pom.xml, build.gradle(.kts), *.csproj, build.sbt.",
|
|
3115
3303
|
"List the language that owns the backend/data code first \u2014 that is the one an ingestion script will be written in.",
|
|
3116
|
-
"If a superset language is found, exclude the subset language. TS-over-JS.",
|
|
3304
|
+
"If a superset language is found, exclude the subset language. TS-over-JS. Kotlin-over-Java when Kotlin is primary.",
|
|
3117
3305
|
"If a meta-framework is used, exclude the framework. Next-over-React.",
|
|
3118
3306
|
"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).",
|
|
3119
3307
|
"Return the exact version",
|
|
@@ -3164,7 +3352,7 @@ var MODE_CONFIG = {
|
|
|
3164
3352
|
"Analyze the codebase to find the data entities (models) that should be ingested into Algolia.",
|
|
3165
3353
|
"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).",
|
|
3166
3354
|
"Inspect the source of each entity to extract real field names for attributes \u2014 do not guess or leave attributes empty.",
|
|
3167
|
-
"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.",
|
|
3355
|
+
"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.",
|
|
3168
3356
|
"Prefer domain models (e.g. Document, Product, User) over framework or infrastructure types.",
|
|
3169
3357
|
"Use as few tools as possible, but do not guess. If you cannot find any entities, return an empty array.",
|
|
3170
3358
|
"Ignore directories that may be related to testing, like `/fixtures`, `/tests`, etc",
|
|
@@ -3187,7 +3375,7 @@ var MODE_CONFIG = {
|
|
|
3187
3375
|
verification: {
|
|
3188
3376
|
instructions: [
|
|
3189
3377
|
"Analyze the codebase to determine which code-quality tools are available to validate changes.",
|
|
3190
|
-
"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.",
|
|
3378
|
+
"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.",
|
|
3191
3379
|
'Return the tool names as an array, e.g. ["eslint", "prettier", "tsc"] or ["ruff", "mypy"].',
|
|
3192
3380
|
"Use as few tools as possible, but do not guess. If you cannot find any, return an empty array.",
|
|
3193
3381
|
"Ignore directories that may be related to testing, like `/fixtures`, `/tests`, etc",
|
|
@@ -3215,7 +3403,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3215
3403
|
// package.json
|
|
3216
3404
|
var package_default = {
|
|
3217
3405
|
name: "@algolia/wizard",
|
|
3218
|
-
version: "0.8.0-rc.
|
|
3406
|
+
version: "0.8.0-rc.65.53",
|
|
3219
3407
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3220
3408
|
type: "module",
|
|
3221
3409
|
engines: {
|
|
@@ -3681,7 +3869,7 @@ ${JSON.stringify(s.output, null, 2)}`
|
|
|
3681
3869
|
}
|
|
3682
3870
|
function formatReviewSummary(result) {
|
|
3683
3871
|
const nextStepLines = result.nextSteps.map((step) => {
|
|
3684
|
-
const isIngestCommand = step.includes("algolia-wizard/");
|
|
3872
|
+
const isIngestCommand = step.includes("algolia-wizard/") || step.includes("AlgoliaWizardIngest");
|
|
3685
3873
|
const isWorktreeCommand = step.includes("/worktrees/");
|
|
3686
3874
|
return {
|
|
3687
3875
|
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.
|